2010-11-08 139 views
42

我在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服务和索引编号应该来自客户端NT可以发送100000作为索引,这将迫使MongoDB创建一个具有空值的100000个索引的数组。

是否有任何其他的方式来更新这些对象嵌套在那里我可以参照对象的ID,而不是它的位置,或者可能的方法来检查,如果提供的索引超出范围的查询使用它之前?

+4

我建议你重新考虑这一模式,并找到不同的设计,这样就可以利用该MongoDB中提供的强大功能。有没有简单/超级有效的方式来更新数组AFAIK中的特定项目。你可以重新设计这个,这样你就可以充分利用'addToSet','pop'和其他数组运算符吗? – brianz 2010-11-08 18:29:21

+0

谢谢你的建议,是的,我可以,事实上我已经做到了。提出这个问题,我只是想确定我没有失去任何东西。 – Anton 2010-11-08 22:50:30

+2

我也面临同样的问题。所以你可以发布你的样本重新设计的模式? – Damodaran 2012-11-12 10:27:11

回答

26

这里的大问题,你需要利用蒙戈的“addToSet”和“推”的操作?如果您真的打算修改数组中的单个项目,那么您应该将这些数组构建为对象。

这里是我会怎么构建这样的:

{ 
    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”概念。

此功能已在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} ] })

+0

它将如何工作它的项目是一个数组。 – kapad 2013-06-27 21:36:26

+0

如果'items'是一个数组,'$ set'命令不起作用。您需要以不同的方式构造数据并利用'$ addToSet'。 – 2013-06-28 05:42:53

+1

我正在寻找一个使用'$'的解决方案。像'items。$'这样的东西可以遍历项目数组的所有元素并进行我想要的更改。任何想法的语法会是这样的事情。它可以完成吗? – kapad 2013-06-28 21:15:58

3

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