【问题标题】:How to update an element within an array of a sub-document in Mongodb如何更新 Mongodb 中子文档数组中的元素
【发布时间】:2014-04-03 03:33:49
【问题描述】:

尝试在 Mongo 中更新子文档数组中的元素时遇到问题。如果我考虑集合“资源”中的以下文档

{
    "_id": 1,
    "resources": [
        {
            "resource_id": 1,
            "resource_list": ["item1","item2"]
        },
        {
            "resource_id": 2,
            "resource_list": ["item4","item3"]
        }
    ]
}

我想用 "item5" 等其他值更新 "item4" 以获取 "resource_id" = 2

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

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

对此的任何帮助将不胜感激。

【问题讨论】:

    标签: mongodb mongodb-update


    【解决方案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);
        }
      }
    })
    

    【讨论】:

    • 感谢 Gergo 对此的回复。这真的很有帮助,为了避免这个操作不止一个语句,我稍微改变了我的模型。再次感谢您对此的帮助
    【解决方案2】:

    符号$只修改搜索中最后一个数组的最后位置,可以使用$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"}})
    

    修饰符不允许字段名称重复

    【讨论】:

    • 感谢 Carlos 的回复,我没有尝试 $addToSet 但在相同的查询中尝试了 $push 和 $pull 但没有奏效。你是说如果我使用 $addToSet 而不是 $push 那么它应该可以工作吗?
    • 不,MongoDB 说“字段名称重复不允许使用修饰符”,简而言之,MongoDB 不允许在同一字段的同一咨询中删除和添加值。
    猜你喜欢
    • 1970-01-01
    • 2012-09-28
    • 2011-12-19
    • 2016-12-31
    • 1970-01-01
    • 2014-04-01
    • 2016-11-04
    • 1970-01-01
    • 2017-01-05
    相关资源
    最近更新 更多