Home > Enterprise >  mongoose: Add an element into an empty child array under
mongoose: Add an element into an empty child array under

Time:01-01

I have the following schema, and I have a document of the story in mongodb, this story doesn't have values for key "fans", which is an array. I would like to add an element to this array. However, I tried to use fans.push, fans.pop or fans = [element], it doesn't work. Please help me to understand what is the best way of doing this.

const personSchema = Schema({
  _id: Schema.Types.ObjectId,
  name: String,
  age: Number,
  stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});

const storySchema = Schema({
  author: { type: Schema.Types.ObjectId, ref: 'Person' },
  title: String,
  fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
});

const Story = mongoose.model('Story', storySchema);
const Person = mongoose.model('Person', personSchema);

   const story1 = new Story({
     title: 'Casino Royale',
     author: author._id    // assign the _id from the person
   });

const fan = new Person({
  _id: new mongoose.Types.ObjectId(),
  name:'Fan 001',
  age:38
});
fan.save(function(err){
  if (err) return handleError(err);
  const story1=Story.findOne({title:'Casino Royale'});
  story1.fans=[fan._id];
  story1.save(function (err){
    if (err) return handleError(err);
  });
});

when I run this script, I have got the following error: enter image description here

CodePudding user response:

here const story1=Story.findOne({title:'Casino Royale'}); findOne is not returning the document hence save is not defined for that. as mentioned in the documentation it returns a query try writing your code using promise and await for the response

const story1 = await Story.findOne({title:'Casino Royale'});

CodePudding user response:

So to make this whole thing work you need a few steps:

Step 1: You need to save the story1 you created else the findOne wont return anything

Step 2: You need to await database calls since they are async

I will provide a code making use of the database update methods, it is a lot cleaner and faster to directly push it in the database.

So here is your code corrected:

const personSchema = Schema({
            _id: Schema.Types.ObjectId,
            name: String,
            age: Number,
            stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
        });

        const storySchema = Schema({
            author: { type: Schema.Types.ObjectId, ref: 'Person' },
            title: String,
            fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
        });

        const Story = mongoose.model('Story', storySchema);
        const Person = mongoose.model('Person', personSchema);

        const author = { name: 'asdsd', _id: "aaaaaaaaaaaaaaaaaaaaaaaa" } // Note I hardcoded an id here

        const story1 = new Story({
            title: 'Casino Royale',
            author: author._id // Assign the _id from the person
        });
        await story1.save() // Await

        const fan = new Person({
            _id: new mongoose.Types.ObjectId(),
            name: 'Fan 001',
            age: 38
        });
        await fan.save(async function(err) { // Await since we have to await the database
            if (err) return handleError(err);
            const story1 = await Story.findOne({ title: 'Casino Royale' }); // Await database
            console.log(story1)
            story1.fans.push(fan._id);
            await story1.save(function(err) { // Await again
                if (err) return handleError(err);
            });
        });

Here is the code in a better version (Note that the schema doesnt have an _id anymore since it is provided by mongoDb):

const personSchema = Schema({
            name: String,
            age: Number,
            stories: [{ type: Schema.Types.ObjectId, ref: 'Story' }]
        });

        const storySchema = Schema({
            author: { type: Schema.Types.ObjectId, ref: 'Person' },
            title: String,
            fans: [{ type: Schema.Types.ObjectId, ref: 'Person' }]
        });

        const Story = mongoose.model('Story', storySchema);
        const Person = mongoose.model('Person', personSchema);

        const author = { name: 'asdsd', _id: "aaaaaaaaaaaaaaaaaaaaaaaa" } // Note I hardcoded an id here

        // Create a Story that is immediately saved in the database and gets an _id by mongoDb
        await Story.create({
            title: 'Casino Royale',
            author: author._id
        })

        // Create a Person that is immediately saved in the database and gets an _id by mongoDb
        const fan = await Person.create({
            name: 'Fan 001',
            age: 38
        })

        // Add the Person to the stories fans array
        const story1 = await Story.findOneAndUpdate(
            { title: 'Casino Royale' }, 
            { $push: { 'fans': fan._id } }, 
            { new: true })

        console.log(story1)
  • Related