There are a few posts about this (here and here, for example), but none of them use a native Mongoose method for this. (The first one uses $set
, the second one uses the extend
npm package. Seems like there should be a "native mongoose" way to do this though.
var blogPostSchema = new mongoose.Schema({
title: String,
comments: [{
body: String
}]
});
Here's what I tried originally:
BlogPost.findById(req.params.postId, function (err, post) {
var subDoc = post.comments.id(req.params.commentId);
subDoc = req.body;
post.save(function (err) {
if (err) return res.status(500).send(err);
res.send(post);
});
});
Problem is this line: subDoc = req.body
isn't actually changing the parent doc's subDoc, but rather is just passed by reference. Nothing actually changes in the database after a save()
call.
The extend
package fixes this by merging the two objects together, as shown in the second SO post linked above (and again here). But isn't there a way to get around this using some Mongoose API method? I can't find anything in the documentation about it (only how to add new subdocs and remove subdocs).
An alternative I wrote was this:
for (var key in subDoc) {
subDoc[key] = req.body[key] || subDoc[key];
}
which also works, but I wasn't sure if there was anything dangerous about doing it this way. Maybe this is the best way?
Thanks in advance!
The reason subDoc = req.body
doesn't work is that it is replacing the reference that was created by the first assignment to subDoc
with a brand new reference to req.body
(assuming it is an object and not a string). This has nothing to do with Mongoose but just how references work in general.
var objA = { a: 1, b: 2};
var objB = { a: 'A', b: 'B'};
var objC = objA;
console.log('Assigning ref to objC from objA', {objA, objB, objC});
// It should console.log the following:
// Assigning ref to objC from objA {
// "objA": {
// /**id:2**/
// "a": 1,
// "b": 2
// },
// "objB": {
// "a": "A",
// "b": "B"
// },
// "objC": /**ref:2**/
// }
//
objC = objB;
console.log('Replacing ref to objC with objB', {objA, objB, objC});
// It should console.log the following:
// Replacing ref to objC with objB {
// "objA": {
// "a": 1,
// "b": 2
// },
// "objB": {
// /**id:3**/
// "a": "A",
// "b": "B"
// },
// "objC": /**ref:3**/
// }
You can use the Document.#set
method. Just provide it an object (in this case req.body
) that mirrors the document's structure with the values you want to set.
BlogPost.findById(req.params.postId, function(err, post) {
var subDoc = post.comments.id(req.params.commentId);
subDoc.set(req.body);
// Using a promise rather than a callback
post.save().then(function(savedPost) {
res.send(savedPost);
}).catch(function(err) {
res.status(500).send(err);
});
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With