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:
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)