单个语句中使用多个Mongo更新运算符?

22

我能否将 $pushAll 和 $inc 合并到一个语句中?

在合并之前,以下代码可以正常工作:

db.createCollection("test");
db.test.insert({"name" : "albert", "bugs" : []});

db.test.update({"name":"albert"}, 
    {"$pushAll" : {"bugs" : [{"name":"bug1", "count":1}]}});

db.test.update({"name":"albert"}, 
    {"$inc" : {"bugs.0.count" : 1}});

db.test.update({"name":"albert"}, 
    {"$pushAll" : {"bugs" : [{"name":"bug2", "count":1}]}});

但是,当我尝试将它们组合在一起时:

db.createCollection("test");
db.test.insert({"name" : "albert", "bugs" : []});

db.test.update({"name":"albert"}, 
    {"$pushAll" : {"bugs" : [{"name":"bug1", "count":1}]}});

db.test.update({"name":"albert"}, 
    {
       "$pushAll" : {"bugs" : [{"name":"bug2", "count":1}]}, 
       "$inc" : {"bugs.0.count" : 1}
    }
);

发生这个错误的原因是:

have conflicting mods in update

我想知道是否有可能做到这一点,而且我还想结合不止pushAll和inc,但我不确定是否支持?


更新于2012年3月23日

我尝试在数组的不同元素上多次使用$inc,并且它可以工作(尽管不正确。引用下面的答案以澄清为什么这不起作用以及什么起作用:正确增加两个字段的方法如下:> db.test.update({"name":"albert"}, {"$inc" : {"bugs.0.count" : 1, "bugs.1.count" : 1}})

db.test.update({"name":"albert"}, 
  {
    "$inc" : {"bugs.0.count" : 1}, 
    "$inc" : {"bugs.1.count" : 1}
  }
);

同时在数组的不同元素上,使用 $set 和 $inc 的组合也可以实现:

db.test.update({"name":"albert"}, 
  {
    "$set" : {"bugs.0.test" : {"name" : "haha"}}, 
    "$inc" : {"bugs.0.count" : 1}, 
    "$inc" : {"bugs.1.count" : 1}
  }
);

但是将它们中的任何一个与$push或$pushAll结合使用,都会出现错误。

所以,我目前的结论是,问题不在于对同一数组中的多个元素执行多个操作,而在于将这些操作与$push或$pushAll组合使用可能会改变数组是问题的根源。


2
显然,您不能为同一字段设置两个修饰符。 - Sergio Tulentsev
@SergioTulentsev:我认为它们是两个不同的字段:“bugs”和“bugs.0.count”吗? - Bertie
那我就不知道了。而且MongoDB可能会有不同的想法 :) - Sergio Tulentsev
@SergioTulentsev:是的,我当时有点希望。非常感谢 :-) - Bertie
1个回答

30

可以在同一文档上执行多个更新操作,只要这些更新操作不冲突(因此会出现“在更新中有冲突的修改”错误)。

由于 "$push" : {"bugs" : [{"name":"bug1", "count":1}]} 和 "$inc" : {"bugs.0.count" : 1} 都试图修改文档的同一部分(即 "bugs" 数组),它们发生了冲突。

如果每个更新操作影响文档的不同部分,则可以将多个更新操作合并:

例如:

> db.test.drop()
true
> db.test.save({ "_id" : 1, "name" : "albert", "bugs" : [ ] })
> db.test.update({"name":"albert"}, {"$pushAll" : {"bugs" : [{"name":"bug1", "count":1}]}, "$inc" : {"increment" : 1}, $set:{"note":"Here is another field."}})
> db.test.find()
{ "_id" : 1, "bugs" : [ { "name" : "bug1", "count" : 1 } ], "increment" : 1, "name" : "albert", "note" : "Here is another field." }
> 

更新包含三种不同的操作($pushAll, $inc 和 $set),但成功完成,因为每个操作影响文档的不同部分。

我知道这并不完全是你希望做的,但希望它能让你更好地了解更新的工作原理,并为您的应用程序提供一些重构更新和/或文档以执行所需功能的想法。祝你好运。


感谢 Marc。很巧合的是,当你在回答这个问题时,我正在阅读你在 http://groups.google.com/group/mongodb-user/browse_thread/thread/f99afd1e09ac0934/9ca43991ff862a78 上的答案。不管怎样,这是否意味着对同一数组中的元素进行多个更新操作基本上不受支持?如果是的话,也许将来有计划支持吗?谢谢。 - Bertie
我尝试使用$inc对同一数组部分进行多次修改,它起作用了:db.test.update({"name":"albert"}, {"$inc" : {"bugs.0.count" : 1}, "$inc" : {"bugs.1.count" : 1}}); 我认为只有在将$push和其他操作结合在同一个数组中时才会出现这个问题? - Bertie
4
正如你所发现的,只要更新不冲突,可以同时更新数组中的多个元素。冲突是因为试图在修改其元素的同时更改数组的大小引起的。顺带一提,你可能会注意到更新“{"$inc" : {"bugs.0.count" : 1}, "$inc" : {"bugs.1.count" : 1}}”不能按预期工作。(这是因为更新文档具有重复的"$inc"键。)增加两个字段的正确方法如下:
db.test.update({"name":"albert"}, {"$inc" : {"bugs.0.count" : 1, "bugs.1.count" : 1}})
- Marc
哇,我没有意识到重复的键"$inc"会有问题。谢谢! - Bertie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接