【问题标题】:Updating nested arrays in mongodb更新 mongodb 中的嵌套数组
【发布时间】:2011-05-06 12:28:24
【问题描述】:

我在 mongodb 中有一个文档,其中包含需要更新的 2 级深度嵌套对象数组,如下所示:

{
    id: 1,
    items: [
        {
            id: 2,
            blocks: [
                {
                    id: 3
                    txt: 'hello'
                }
            ]
        }
    ] 
}

如果只有一级深度数组,我可以使用位置运算符来更新其中的对象,但对于第二级,我想出的唯一选择是使用位置运算符和嵌套对象的索引,如下所示:

db.objects.update({'items.id': 2}, {'$set': {'items.$.blocks.0.txt': 'hi'}})

这种方法有效,但对我来说似乎很危险,因为我正在构建一个 Web 服务,并且索引号应该来自客户端,它可以发送 100000 作为索引,这将迫使 mongodb 创建一个包含 100000 个空值索引的数组。

是否有任何其他方法可以更新此类嵌套对象,我可以在其中引用对象的 ID 而不是它的位置,或者在查询中使用它之前检查提供的索引是否超出范围?

【问题讨论】:

  • 我建议您重新访问此模式并找到不同的设计,以便您可以利用 MongoDB 提供的功能。将没有简单/超级有效的方法来更新数组 AFAIK 中的特定项目。你能否重新设计它,以便利用addToSetpop 和其他数组运算符?
  • 感谢您的建议,是的,我可以,事实上我已经这样做了。问这个问题我只是想确定我没有遗漏任何东西。
  • 我也面临同样的问题。那么你能发布你的示例重新设计的架构吗?

标签: arrays mongodb nested


【解决方案1】:

db.col.update({"items.blocks.id": 3},
{ $set: {"items.$[].blocks.$[b].txt": "bonjour"}},
{ arrayFilters: [{"b.id": 3}] }
)

https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/#update-nested-arrays-in-conjunction-with

【讨论】:

    【解决方案2】:

    在盖茨的回答的基础上,我想出了这个适用于嵌套对象数组的解决方案:

    db.objects.updateOne({
      ["items.id"]: 2
    }, {
      $set: {
        "items.$.blocks.$[block].txt": "hi",
      },
    }, {
      arrayFilters: [{
        "block.id": 3,
      }],
    });
    

    【讨论】:

      【解决方案3】:

      MongoDB 3.6 添加了all positional operator $[],因此如果您知道需要更新的块的 id,您可以执行以下操作:

      db.objects.update({'items.blocks.id': id_here}, {'$set': {'items.$[].blocks.$.txt': 'hi'}})
      

      【讨论】:

        【解决方案4】:

        这是一个大问题,您是否需要利用 Mongo 的“addToSet”和“push”操作?如果您真的打算只修改数组中的单个项目,那么您可能应该将这些数组构建为对象。

        这是我的结构:

        {
            id: 1,
            items: 
                { 
                  "2" : { "blocks" : { "3" : { txt : 'hello' } } },
                  "5" : { "blocks" : { "1" : { txt : 'foo'}, "2" : { txt : 'bar'} } }
                }
        }
        

        这基本上将所有内容转换为 JSON 对象而不是数组。你失去了使用$push$addToSet 的能力,但我认为这让一切变得更容易。例如,您的查询将如下所示:

        db.objects.update({'items.2': {$exists:true} }, {'$set': {'items.2.blocks.0.txt': 'hi'}})

        您还会注意到我已经转储了“ID”。当您嵌套这样的东西时,您通常可以简单地使用该数字作为索引来替换“ID”。现在隐含了“ID”概念。

        此功能已在 3.6 中添加expressive updates

        db.objects.update( {id: 1 }, { $set: { 'items.$[itm].blocks.$[blk].txt': "hi", } }, { multi: false, arrayFilters: [ { 'itm.id': 2 }, { 'blk.id': 3} ] } )

        【讨论】:

        • 如果items 是一个数组,那么$set 命令不起作用。您需要以不同的方式构建数据并利用 $addToSet
        • 我正在寻找使用 $ 的解决方案。像items.$ 这样的东西会遍历项目数组的所有元素并进行我想要的更改。任何想法这样的语法是什么。还能做到吗?
        • 我同意@kapad,我对使用多个位置运算符更感兴趣:'items.$.blocks.$.txt'...不幸的是,这样的功能仍然不可用查看这张票:@ 987654322@登录mongodb的JIRA为本期投票!
        • 我来这里是为了updating nested arrays in mongodb,但这个答案对这个问题帮助不大。投反对票。
        • 这实际上是个好主意。但是,您将如何进行这种性质的查询:“查找所有嵌套 txt 值等于 hello 的项目”
        【解决方案5】:

        您使用的 id 是线性数字,它必须来自某个地方,例如“max_idx”或类似的附加字段。 这意味着查找 id 然后更新。 UUID/ObjectId 可用于 id,这将确保您也可以使用分布式 CRUD。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-10-22
          • 2017-09-11
          相关资源
          最近更新 更多