22

Can i combine $pushAll and $inc in one statement ?

Before combine, this works fine :

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}]}});

But when i try combining it like this :

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}
    }
);

This error happens :

have conflicting mods in update

I wonder it is possible to do this, and also, i imagine combining more than just pushAll and inc, but i am not sure whether this is supported or not ?


update march 23, 2012

I tried multiple $inc on different elements of an array, and it works (although not correctly. quoted from the answer below to clarify why this doensnt work well and what works : The correct way to increment both fields is as follows: > 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}
  }
);

And this combination of $set and $inc on different elements of an array also works :

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

But combine any of these with $push or $pushAll, all will go error.

So, my current conclusion is, it is not about multiple operations on multiple elements within the same array which is the problem, but combining these operations with $push or $pushAll that can change the the array is the problem.

Bertie
  • 17,277
  • 45
  • 129
  • 182

1 Answers1

30

Multiple updates may be performed on the same document, as long as those updates do not conflict (hence the "have conflicting mods in update" error).

Because "$push" : {"bugs" : [{"name":"bug1", "count":1}]} and "$inc" : {"bugs.0.count" : 1} are both attempting to modify the same portion of the document (namely the "bugs" array), they conflict.

Multiple updates may be combined if each affects a different part of the document:

for example:

> 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." }
> 

The update contained three different operations ($pushAll, $inc, and $set), but was able to complete successfully, because each operation affected a different part of the document.

I realize this is not exactly what you were hoping to do, but hopefully it will provide you with a little better understanding of how updates work, and perhaps provide some ideas how your updates and/or documents may be restructured to perform the functionality that your application requires. Good luck.

Marc
  • 5,488
  • 29
  • 18
  • Thanks Marc. Strange coincidence that i was reading your answer at http://groups.google.com/group/mongodb-user/browse_thread/thread/f99afd1e09ac0934/9ca43991ff862a78 while you are typing an answer of this question. Anyway, does this mean that the multiple update operations on elements inside the same array is basically not supported ? And if yes, perhaps any plan on it to be supported in the future ? Thank you. – Bertie Mar 22 '12 at 15:45
  • I tried multiple modifications the same array portion using $inc and it worked : db.test.update({"name":"albert"}, {"$inc" : {"bugs.0.count" : 1}, "$inc" : {"bugs.1.count" : 1}}); I think this problem only happens when i combine $push and other operations within the same array ? – Bertie Mar 23 '12 at 00:10
  • 4
    As you have discovered, as long as the updates do not conflict, multiple elements in an array may be updated at the same time. The conflict comes from attempting to change the size of the array at the same time as modifying one of its elements. As an aside, you may notice that the update "{"$inc" : {"bugs.0.count" : 1}, "$inc" : {"bugs.1.count" : 1}}" does not work as expected. (This is because the update document has a duplicate key, "$inc".) The correct way to increment both fields is as follows: > db.test.update({"name":"albert"}, {"$inc" : {"bugs.0.count" : 1, "bugs.1.count" : 1}}) – Marc Mar 26 '12 at 22:03
  • Whoa i didnt realize the duplicate key "$inc" was problematic. Thanks ! – Bertie Mar 27 '12 at 04:57