更新mongodb中的嵌套数组

wfypjpf4  于 2023-03-01  发布在  Go
关注(0)|答案(6)|浏览(234)

我在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而不是它的位置,或者在查询中使用它之前检查提供的索引是否越界?

t1rydlwq

t1rydlwq1#

这里有一个大问题,你需要利用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”的概念现在已经隐含了。
此功能已在Python 3.6中添加,并进行了表达更新。
db.objects.update( {id: 1 }, { $set: { 'items.$[itm].blocks.$[blk].txt': "hi", } }, { multi: false, arrayFilters: [ { 'itm.id': 2 }, { 'blk.id': 3} ] } )

nwo49xxi

nwo49xxi2#

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

w3nuxt5m

w3nuxt5m3#

基于盖茨的回答,我想出了这个解决方案,它可以处理嵌套对象数组:

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

xeufq47z4#

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

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

nukf8bse5#

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

3zwjbxry

3zwjbxry6#

这是find_one_and_update的pymongo函数。我搜索了很多才找到pymongo函数。希望这会有用

find_one_and_update(filter, update, projection=None, sort=None, return_document=ReturnDocument.BEFORE, array_filters=None, hint=None, session=None, **kwargs)

示例

db.pymongo_object.find_one_and_update( filter = {'id' : 1}, update= {$set: {"items.$[array1].blocks.$[array2].txt": "hi"}}, array_filters =[{"array1.id" :2}, {"array2.id": 3}])

另请参见pymongo documentation

相关问题