Reputation: 1468
I'm trying to push subdocuments into a parent document using push()
method.
After that, I want to save the parent document calling save()
method on it. But the result is an empty array.
I've also tried to call parent.markModified('children')
before saving the parent doc, but it makes no difference.
Below is my Schemas and the code that should save the subdocuments :
Schema :
const profileSessionSchema = mongoose.Schema({
firstName: { type: String, trim:true},
...
realisations : [realisationSchema],
});
ProfileSession = mongoose.model('ProfileSession',profileSessionSchema);
const realisationSchema = mongoose.Schema({
profileId :{ type: mongoose.Schema.Types.ObjectId, ref: 'ProfileSession'},
...
type : { type: String, enum:conf.wallTypes, required:true, default:'classic'},
});
Realisation = mongoose.model('Realisation', realisationSchema);
ProfileSession.create(profileData,function(err,profile){
for(j=0;j<realisations.length;j++){ // realisations array is not empty
var r = Realisation(realisations[j])
r.save(function(a,real){
profile.realisations.push(real)
})
}
profile.markModified('realisations')
profile.save()
})
The profile document is indeed created in DB, but without the realisations subdocuments. I've found plenty of subjects about this, and it appears that the method markModified
should solve the issue. But it does not in my case and I can't understand why...
Thank you for you help. Cheers
Upvotes: 3
Views: 1275
Reputation: 2636
This is "A" correct/tested general structure of your code, If you're trying to create a document(child) within another document(parent).
My mistake was to order the save() method and that I'm not used to indenting Node code.
General guideline
Actual code
exports.addNewParentWithAChild = (req, res) => {
/** 1. create parent object **/
const parent = new Parent({
parentName: req.body.parentName,
});
/** 2. save parent **/
parent.save((err, u) => {
if (err) {
res.status(500).send({ message: err });
return;
}
/** 3. create child object **/
const child = new Parent({
childName: req.body.childName,
});
/** 4. save child **/
child.save((err, c) => {
if (err) {
res.status(500).send({ message: err });
return;
}
/** 5. attach child object to parent **/
p.children = [child]; //I created one child, so my array has one child object, (you can use map and push for multiple children adding at one)
/** 6. save parent again with the child **/
parent.save((err, p) => {
if (err) {
res.status(500).send({ message: err });
return;
} else {
res
.status(200)
.send({ message: "success", lastParent: p, childAdded: c });
}
});
});
});
};
Upvotes: 0
Reputation: 1896
callback won't wait its non-blocking so it will immediately execute profile.save
before push anything into array, you should try to save it inside the callback or you should use async/await. I am posting both solution where we will save profile inside of callback and using async/await. I would prefer you using async/await. see both solution below :
within callback:
ProfileSession.create(profileData, function(err, profile) {
for (j = 0; j < realisations.length; j++) { // realisations array is not empty
var r = Realisation(realisations[j])
r.save(function(a, real) {
profile.realisations.push(real)
profile.markModified('realisations')
profile.save()
})
}
})
with async/await :
async function foo() {
let newProfileData = await new ProfileSession(profileData)
let profile = newProfileData.save();
for (let j = 0; j < realisations.length; j++) { // realisations array is not empty
let r = new Realisation(realisations[j])
let real = await r.save();
profile.realisations.push(real);
profile.markModified('realisations')
profile.save()
}
}
foo()
Upvotes: 1
Reputation: 322
I think your for loop is iterating too quickly for r.save() to complete and then it's calling profile.save() before it actually saves. Maybe put some console.log inside of your r.save() and then above your profile.save() so you can see the order in which each get called
Upvotes: 2
Reputation: 18515
If you are actually trying to create new Realisation
then you would need to use the keyword to create a new model from the schema:
ProfileSession.create(profileData,function(err,profile){
for(j=0;j<realisations.length;j++){ // realisations array is not empty
var r = new Realisation(realisations[j]) // <-- use new
r.save(function(a,real){
profile.realisations.push(real)
})
}
profile.markModified('realisations')
profile.save()
})
Upvotes: 0