Home > Net >  Updating a Subdocument in MongoDB
Updating a Subdocument in MongoDB

Time:06-26

I am trying to create a database for my Giveaway Bot. It consist of 2 collections, Main (holding settings) and Giveaway which is nested in under the Main collection. I can create my giveaway's without problems. However I want to add some data later on using findOneAndUpdate.

Running the code below I always get this error: Updating the path 'giveaways.duration' would create a conflict at 'giveaways'. Can anyone help solving this issue ?

schema.js

const giveawaySchema = new mongoose.Schema({  
    _id: String,
    destination: String,
    duration: String,
    winners: String,
    price: String,
})

const mainSchema = new mongoose.Schema({
    _id: String,
    log_channel_id: String,
    admin_roles: [],
    giveaways: [giveawaySchema],

const Main = mongoose.model("mainSchema", mainSchema);
const Giveaway = mongoose.model("giveawaySchema", giveawaySchema);

module.exports = { Main, Giveaway }
});

Part of my code used for updating:

const mongoose = require("mongoose")
const {Main, Giveaway} = require("../models/schema.js")

const newestGiveaway = await Main.findOneAndUpdate(
    {
        _id: guildId,
        'giveaways._id': giveaway_id,
    },  
    {   
        "$set":{
            "giveaways.duration": "3d",
            "giveaways.winners": "20",
            "giveaways.price": "Price to Win",
         },
    },
    {
        upsert: true,
    }
        

Thank you for your help :)

A small side question. I have fetched the Main document (the parent) before already can I make my search cheaper/ more efficent by only searching through this instead of running the findOneandUpdate method on the whole database ?

Edit 1:

I found that it is neccesary to use the $ operator and have updated my code. However I still get the same error:

{
   $set:{
      "giveaways.$.duration": "3d",
      "giveaways.$.winners": "20,
      "giveaways.$.price": "Price to Win",
   },
},

Edit 2:

Just to clarify, the creation and nesting of the giveawaySchemas works but I am not able to update the nested document by using the code above. My child component is already created by using the code below. I now want to update this child (newGiveaway with _id of 1)

const currentGuild = await Main.findOne({_id: guildId})

const newGiveaway = await Giveaway.create({
    _id: 1,
    destination: 12345678,
});

currentGuild.giveaways.push(newGiveaway)

CodePudding user response:

in mainSchema you define giveaways field as an array of giveawaySchema object. so you have to treat it as an array, not an object. If you want to treat it as an object, you will have to update mainSchema by removing square bracket at giveawaysSchema. Relevant Question for how to pushing item into mongo array

CodePudding user response:

You can change your schema declaration to use a ref to the giveawaySchema:

const giveawaySchema = new mongoose.Schema({  
    _id: String,
    destination: String,
    duration: String,
    winners: String,
    price: String,
})

const mainSchema = new mongoose.Schema({
    _id: String,
    log_channel_id: String,
    admin_roles: [],
    giveaways: [{
        type: mongoose.Schema.Types.ObjectId,
        ref: 'giveawaySchema'
    }],

const Main = mongoose.model("mainSchema", mainSchema);
const Giveaway = mongoose.model("giveawaySchema", giveawaySchema);

module.exports = { Main, Giveaway }

Then, you will just need to update your giveaways directy:

const mongoose = require('mongoose');
const { Giveaway } = require('../models/schema.js');

const newestGiveaway = await Main.findByIdAndUpdate(
  giveaway_id,
  {
    duration: '3d',
    winners: '20',
    price: 'Price to Win',
  },
  {
    new: true,
  }
);
  • Related