更新 mongodb 中的嵌套数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4121666/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Updating nested arrays in mongodb
提问by src091
I have a document in mongodb with 2 level deep nested array of objects that I need to update, something like this:
我在 mongodb 中有一个文档,其中包含需要更新的 2 级深度嵌套对象数组,如下所示:
{
id: 1,
items: [
{
id: 2,
blocks: [
{
id: 3
txt: 'hello'
}
]
}
]
}
If there was only one level deep array I could use positional operator to update objects in it but for second level the only option I've came up is to use positional operator with nested object's index, like this:
如果只有一层深数组,我可以使用位置运算符来更新其中的对象,但对于第二级,我提出的唯一选择是使用带有嵌套对象索引的位置运算符,如下所示:
db.objects.update({'items.id': 2}, {'$set': {'items.$.blocks.0.txt': 'hi'}})
This approach works but it seems dangerous to me since I'm building a web service and index number should come from client which can send say 100000 as index and this will force mongodb to create an array with 100000 indexes with null value.
这种方法有效,但对我来说似乎很危险,因为我正在构建一个 Web 服务,索引号应该来自客户端,它可以发送 100000 作为索引,这将强制 mongodb 创建一个包含 100000 个索引且值为空的数组。
Are there any other ways to update such nested objects where I can refer to object's ID instead of it's position or maybe ways to check if supplied index is out of bounds before using it in query?
有没有其他方法可以更新此类嵌套对象,我可以在其中引用对象的 ID 而不是它的位置,或者在查询中使用它之前检查提供的索引是否超出范围?
回答by Gates VP
Here's the big question, do you need to leverage Mongo's "addToSet" and "push" operations? If you really plan to modify just individual items in the array, then you should probably build these arrays as objects.
这是一个大问题,您是否需要利用 Mongo 的“addToSet”和“push”操作?如果您真的打算只修改数组中的单个项目,那么您可能应该将这些数组构建为对象。
Here's how I would structure this:
这是我将如何构建它:
{
id: 1,
items:
{
"2" : { "blocks" : { "3" : { txt : 'hello' } } },
"5" : { "blocks" : { "1" : { txt : 'foo'}, "2" : { txt : 'bar'} } }
}
}
This basically transforms everything in to JSON objects instead of arrays. You lose the ability to use $push
and $addToSet
but I think this makes everything easier. For example, your query would look like this:
这基本上将所有内容转换为 JSON 对象而不是数组。你失去了使用的能力$push
,$addToSet
但我认为这让一切变得更容易。例如,您的查询如下所示:
db.objects.update({'items.2': {$exists:true} }, {'$set': {'items.2.blocks.0.txt': 'hi'}})
db.objects.update({'items.2': {$exists:true} }, {'$set': {'items.2.blocks.0.txt': 'hi'}})
You'll also notice that I've dumped the "IDs". When you're nesting things like this you can generally replace "ID" with simply using that number as an index. The "ID" concept is now implied.
您还会注意到我已经丢弃了“ID”。当你嵌套这样的东西时,你通常可以简单地使用该数字作为索引来替换“ID”。现在隐含了“ID”概念。
This feature has been added in 3.6 with expressive updates.
此功能已在 3.6 中添加,并进行了富有表现力的更新。
db.objects.update( {id: 1 }, { $set: { 'items.$[itm].blocks.$[blk].txt': "hi", } }, { multi: false, arrayFilters: [ { 'itm.id': 2 }, { 'blk.id': 3} ] } )
db.objects.update( {id: 1 }, { $set: { 'items.$[itm].blocks.$[blk].txt': "hi", } }, { multi: false, arrayFilters: [ { 'itm.id': 2 }, { 'blk.id': 3} ] } )
回答by Seraj
The ids which you are using are linear number and it has to come from somewhere like an additional field such 'max_idx' or something similar. This means one lookup for the id and then update. UUID/ObjectId can be used for ids which will ensure that you can use Distributed CRUD as well.
您使用的 id 是线性数,它必须来自诸如“max_idx”之类的附加字段之类的某个地方或类似的东西。这意味着先查找 id,然后更新。UUID/ObjectId 可用于 id,这将确保您也可以使用分布式 CRUD。