如何在Mongodb中更新子文档数组中的元素

时间:2014-03-30 22:13:21

标签: mongodb mongodb-update

尝试更新Mongo中子文档数组中的元素时遇到问题。如果我在集合" resource"

中考虑以下文档
{
    "_id": 1,
    "resources": [
        {
            "resource_id": 1,
            "resource_list": ["item1","item2"]
        },
        {
            "resource_id": 2,
            "resource_list": ["item4","item3"]
        }
    ]
}

我想更新"item4"以及"item5"

等其他值"resource_id" = 2

以下语句给出了一个错误:如果没有包含数组的相应查询字段,则无法应用位置运算符。

db.resource.update({"resources.resource_id": 2, "resources.resource_list": "item4"}, {$set: {"resources.$.resource_list.$": "item5"}})

对此的任何帮助都将受到高度赞赏。

2 个答案:

答案 0 :(得分:1)

位置运算符只能在查询中使用一次。这是一个限制,有一个开放的改进票:https://jira.mongodb.org/browse/SERVER-831

解决这个问题的另一种方法可能是推动" item5"到数组并拉出" item4"。像这样:

db.resource.update({ "resources.resource_id": 2, "resources.resource_list": "item4" }, { $pull: { "resources.$.resource_list": "item4" }, $push: { "resources.$.resource_list": "item5" } })

然而,这是不可能的,$pull$push不能用于同一字段的同一查询中。相关票证:https://jira.mongodb.org/browse/SERVER-1050

我看到两个解决方案。一种是执行两个查询。在第一个查询中,您在第二个查询中按" item5"," item4":

db.resource.update({ "resources.resource_id": 2, "resources.resource_list": "item4" }, { $push: { "resources.$.resource_list": "item5" } });
db.resource.update({ "resources.resource_id": 2, "resources.resource_list": "item4" }, { $pull: { "resources.$.resource_list": "item4" } });

如果要在一个查询中执行此操作,可以使用mongo shell。像这样:

db.resource.find({ 'resources.resource_id': 2, 'resources.resource_list': 'item4' }).forEach( function(document) {
  for (var i in document.resources) {
    if (document.resources[i].resource_id == 2) {
      var index = document.resources[i].resource_list.indexOf('item4');
      document.resources[i].resource_list[index] = 'item5';
      db.resource.save(document);
    }
  }
})

答案 1 :(得分:0)

符号$仅修改搜索中最后一个数组的最后位置,您可以使用$addToSet$push添加项目...

 > db.resource.find()
    { "_id" : 1, 
      "resources" : [
                     { "resource_id" : 1,   
                       "resource_list" : [ "item1","item2" ] },     
                     { "resource_id" : 2, 
                       "resource_list" : [ "item4", "item3" ] } ] }

    > db.resource.update({"resources.resource_id": 2, 
                          "resources.resource_list": "item4"},
                         {$addToSet:{"resources.$.resource_list": "item5"}})

    > db.resource.find()
    { "_id" : 1, "resources" : [
                             { "resource_id" : 1, 
                               "resource_list" : [ "item1", "item2" ] },
                             { "resource_id" : 2, 
                               "resource_list" : [ "item4", "item3", "item5" ] } ] }

    > db.resource.update({"resources.resource_id": 2, 
                          "resources.resource_list": "item4"},
                         {$pull: {"resources.$.resource_list": "item4"}})

    > db.resource.find()
    { "_id" : 1, "resources" : [ 
                               { "resource_id" : 1,
                                 "resource_list" : [ "item1", "item2" ] },
                               { "resource_id" : 2,
                                 "resource_list" : [ "item3","item5" ] } ] }

但最好同时运行两个查询?

> db.algo.update({"resources.resource_id": 2,
                  "resources.resource_list": "item4"}, 
                 {$addToSet:{"resources.$.resource_list": "item5"},
                   $pull: {"resources.$.resource_list": "item4"}})

修饰符不允许使用字段名重复