It seems that array subdocs don't save on top-level document.save()
. They only persist their changes on findOneAndUpdate
/findByIdAndUpdate
/ any update operation that bypasses document validation, and only when using $set
.
Here's a repo to reproduce:
https://github.com/varunjayaraman/mongoose-save-array-bug/tree/master
Edit: Sorry, forgot to mention This error occurred on v4.6.0
and v4.5.2
Yeah I'm facing the same problem, always have to first save the document without subdocs and after update it by calling $set
to set my subdocs.
Anybody got a solution?
I've had a similar problem in the past and managed to solve it by marking that property as modified using:
parent.markModified('children')
parent.save();
@VictorGerritsenQLVR While that works, I'd rather document.save()
handle subdoc change detection, unless the lack of that functionality is intentional by design?
@varunjayaraman I agree. I would expect change detection to work on sub-documents. My guess is they are considered a 'Mixed' type as well, which according to the docs, does not track changes:
Since it is a schema-less type, you can change the value to anything else you like, but Mongoose loses the ability to auto detect and save those changes. To "tell" Mongoose that the value of a Mixed type has changed, call the .markModified(path) method of the document passing the path to the Mixed type you just changed.
When I set parts of an array using =, I often have trouble. Using array methods tends to work better. So, instead of changing child as it stands in parent, see if you can figure out a way to do it using the splice method.
Umm yeah @varunjayaraman this is a classic case of the first question on the FAQ: http://mongoosejs.com/docs/faq.html . While mongoose supports ES5, no way to handle directly setting array indexes. Use child.set('grades.3', 50);
instead
@varunjayaraman What was the key part of the code in the repo in your original post? The link is now broken, but your description is very similar to a problem I was just struggling with. I was doing something along the lines of:
Parent.findById(id)
.then(doc => {
doc.children.push(newChild);
doc.save();
}
I ended up switching to the update()
approach to save a roundtrip to the server and avoid the problem.
@numbergames basically change detection on modifying array indexes using something like parentDoc.subDoc[index] = value
won't work. You have to use document.set()
instead
Most helpful comment
I've had a similar problem in the past and managed to solve it by marking that property as modified using: