【问题标题】:Update MongoDB document with nested arrays of sub-documents使用嵌套的子文档数组更新 MongoDB 文档
【发布时间】:2016-11-23 00:07:08
【问题描述】:

我需要更新一个如下所示的 MongoDB 文档:

{
    "_id" : ObjectId("A"),
    "participant" : "John Doe",
    "roles" : [{
        "roleId" : ObjectId("AA"),
        "responsibilities" : [{
            "_id" : ObjectID("AAA"),
            "name" : "resp 1"
        }, {
            "_id" : ObjectID("AAB"),
            "name" : "resp 2"
        }]
    }, {
        "roleId" : ObjectId("AB"),
        "responsibilities" : []
    }]
}

更新有两种形式:

  • 删除所有职责为零的角色子文档...这应该删除具有_id = AB的角色子文档
  • 如果新角色不存在,则添加:{ "roleId" : ObjectId("AC"), "responsibilities" : [] }

【问题讨论】:

  • 是否进行第二次更新,为您刚刚在第一次更新中删除子文档的文档添加新角色?还是您只对没有零责任子文档的文档应用第二次更新?
  • @devonJS 这两个更新操作将分别执行,彼此无关。有时,我可能需要添加新角色,并且我需要确保该角色不存在。可以将其添加为基于索引的约束,但出于其他原因我仍然需要执行检查。在其他时候,我只想在角色的职责为零时删除角色子文档。

标签: mongodb


【解决方案1】:

您的第一次更新:

db.getCollection('collection').update({}, 
    {
        $pull: {
            'roles': {
                'responsibilities': {$size: 0}
            }
        }
    }, {multi: true})

基本上,删除 any 的元素(这是 multi:true 出现的地方)“角色”数组,其中“职责”是一个空数组(或大小为 0)

您的第二次更新,假设一个“新角色”是一个具有空职责数组的角色:

db.getCollection('collection').update(
    {
        'roles': {
            $not: {
                $elemMatch: {
                    'roleId': ObjectId("AC")
                }
            }
        }
    },
    {
        $push: {
            'roles': {
                'roleId': ObjectId("AC"), 
                'responsibilities' : []
            }
        }
    }, {multi: true})

查找没有角色数组的文档,其中元素的职责数组为空,然后使用新的 ObjectId 推送一个新角色,或者您可以自己指定一个。

我已经在 5 个文档的一小部分集合上对此进行了测试,并且似乎可以正常工作,如果您需要任何说明或者它不起作用,请告诉我。

值得注意的是,查询一个必须遍历数组$elemMatch 的数组正是您要查找的内容。修改时,您需要遍历数组 $pull 是您想要使用的。

【讨论】:

  • 对于第二次更新,如果角色数组中尚不存在具有特定 ID 的角色,我想添加该角色。我不应该寻找具有匹配 ID 的现有角色,而不是具有空职责数组的角色吗?
  • @WebUser 对不起,我有点误解了你的问题,请看我上面所做的编辑,它现在正在寻找角色,如果找不到,则将该角色插入跨度>
  • 这更接近我想要的。我将很快对其进行测试。有没有办法将更新指向特定文档,而不是任何或所有文档?另一个问题 - 我可以$elemMatch 使用多个角色 ID 而不是一个?
  • 1) 将第一个参数对象替换为 {'_id': ObjectId('_id of the specific document)},然后取出 {multi: false} 对象 2) 是的,你可以这样做: $elemMatch: {'roleId': {$in: [ID1, ID2, ID3]}} 如果你想查看它是否有任何的roleIds 或者如果你想检查它是否有所有的roleIds 将 $in 替换为 $all .请注意,您将不知道文档缺少哪些,因此您将不知道需要添加什么,如果您只想在每种情况下插入相同的角色,则此方法有效。如果你想准确,你必须多次运行 #2 查询。
  • 我正在使用您的有用答案继续前进。我正在尝试执行更新,其中包括从 roles 数组中删除没有任何责任的子文档(使用 $pull),同时添加(使用 $push)几个新的子文档到相同的roles 数组。由于我试图在单个更新操作中对同一字段进行$pull$push,因此出现错误 - 无法同时更新“角色”和“角色”。尽可能以原子方式执行此操作的推荐方法是什么?
猜你喜欢
  • 1970-01-01
  • 2013-03-19
  • 2017-04-28
  • 1970-01-01
  • 2016-08-04
  • 1970-01-01
  • 1970-01-01
  • 2018-04-23
相关资源
最近更新 更多