使用Mongoose更新数组中的子文档

bob*_*byz 3 javascript mongoose mongodb node.js express

有几篇关于此的文章(例如,在这里这里),但是没有人为此使用本地的Mongoose方法。(第一个使用$set,第二个使用extendnpm包。尽管如此,似乎应该有一种“本地猫鼬”方式。

架构:

var blogPostSchema = new mongoose.Schema({
    title: String,
    comments: [{
        body: String
    }]
});
Run Code Online (Sandbox Code Playgroud)

这是我最初尝试的内容:

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);
    });
});
Run Code Online (Sandbox Code Playgroud)

问题是这一行:subDoc = req.body实际上并没有更改父文档的subDoc,而只是通过引用传递。save()调用后数据库中实际上没有任何更改。

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];
}
Run Code Online (Sandbox Code Playgroud)

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!

Jas*_*ust 9

原因subDoc = req.body不起作用是因为它subDoc用一个全新的引用替换了第一次分配创建的引用req.body(假定它是一个对象而不是字符串)。这与猫鼬无关,只是引用通常是如何工作的。

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**/
// }
Run Code Online (Sandbox Code Playgroud)

您可以使用Document.#set方法。只需为其提供一个对象(在本例中为req.body),该对象即可使用您要设置的值来镜像文档的结构。

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);
  });
});
Run Code Online (Sandbox Code Playgroud)