2013-02-06 97 views
8

我最近开始使用MongoDB,并且有关于更新文档中数组的问题。 我得到的结构是这样的:MongoDB更新数组的多个记录

{ 
"_id" : ObjectId(), 
"post" : "", 
"comments" : [ 
     { 
       "user" : "test", 
       "avatar" : "/static/avatars/asd.jpg", 
       "text" : "....." 
     } 
     { 
       "user" : "test", 
       "avatar" : "/static/avatars/asd.jpg", 
       "text" : "....." 
     } 
     { 
       "user" : "test", 
       "avatar" : "/static/avatars/asd.jpg", 
       "text" : "....." 
     } 
     ... 
    ] 
} 

我试图执行以下查询:

update({"comments.user":"test"},{$set:{"comments.$.avatar": "new_avatar.jpg"}},false,true) 

的问题是其更新的所有文件,但它仅更新在每一个第一个数组元素文件。有没有办法更新所有数组元素,或者我应该尝试手动执行它? 谢谢。

回答

19

您无法在单个更新操作中修改多个数组元素。因此,您必须重复更新才能迁移需要修改多个数组元素的文档。您可以通过每个文档集合中迭代,反复应用的更新与$elemMatch直到文档做这一切的它的相关的备注,例如:

 
db.collection.find().forEach(function(doc) { 
    do { 
    db.collection.update({_id: doc._id, 
          comments:{$elemMatch:{user:"test", 
               avatar:{$ne:"new_avatar.jpg"}}}}, 
         {$set:{"comments.$.avatar":"new_avatar.jpg"}}); 
    } while (db.getPrevError().n != 0); 
}) 

注意,如果这个操作的效率是一个要求你的应用程序,你应该规范你的模式,以便用户头像的位置存储在单个文档中,而不是在每个评论中。

+0

感谢您的回答。那么因为mongo没有加入,我想用博客系统评论,我想在他的评论旁边显示每个用户头像。任何建议我应该如何构建我的模式? –

+0

从概念上讲,你需要在某处存储一个user => avatar map。您可以将每个用户的头像存储在用户文档中(在您的用户集合中),或者,您可以为给定博客条目的评论者在该博客条目的文档字段中存储用户=>头像地图。请参阅http://docs.mongodb.org/manual/applications/database-references/,了解MongoDB中规范化的轻量化处理,以及http://docs.mongodb.org/manual/use-cases/storing-comments/ for一个“用户评论”用例分析。 –

+0

是的,我在看到你的答案之前就想出了解决方案。无论如何非常感谢你@Jason。 –

5

一个解决方案可能是创建一个函数用于forEach并对其进行评估(因此它可以快速运行)。假设您的集合是“文章”,则可以运行以下操作:

var runUpdate = function(){ 
    db.article.find({"comments.user":"test").forEach(function(article) { 
     for(var i in article.comments){ 
      article.comments[i].avatar = 'new_avatar.jpg'; 
     } 
     db.article.save(article); 
    }); 
}; 

db.eval(runUpdate); 
-1

好像你可以这样做:

db.yourCollection.update({"comments.user":"test"},{$set:{"comments.0.avatar": "new_avatar.jpg", "comments.1.avatar": "new_avatar.jpg", etc...}) 

所以,如果你有数组元素的少量已知数量,这可能是更容易一些的事情。如果你想要像“评论。*。头像”的东西 - 不知道如何做到这一点。它可能不是那么好,你有这么多的数据复制寿..

1

如果你知道索引要更新,你可以像这样没有问题做到这一点:

var update = { $set: {} }; 
for (var i = 0; i < indexesToUpdate.length; ++i) { 
    update.$set[`comments.${indexesToUpdate[i]}. avatar`] = "new_avatar.jpg"; 
} 
Comments.update({ "comments.user":"test" }, update, function(error) { 
    // ... 
}); 
  • 注意IDE的必须不会接受语法,但您可以忽略它。