Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pull and addtoset at the same time with mongo

I have a collection which elements can be simplified to this:

{tags : [1, 5, 8]}

where there would be at least one element in array and all of them should be different. I want to substitute one tag for another and I thought that there would not be a problem. So I came up with the following query:

db.colll.update({   tags : 1 },{   $pull: { tags: 1 },   $addToSet: { tags: 2 } }, {   multi: true }) 

Cool, so it will find all elements which has a tag that I do not need (1), remove it and add another (2) if it is not there already. The problem is that I get an error:

"Cannot update 'tags' and 'tags' at the same time"

Which basically means that I can not do pull and addtoset at the same time. Is there any other way I can do this?

Of course I can memorize all the IDs of the elements and then remove tag and add in separate queries, but this does not sound nice.

like image 651
Salvador Dali Avatar asked Jun 19 '14 06:06

Salvador Dali


People also ask

What does $Pull do in MongoDB?

The $pull operator removes from an existing array all instances of a value or values that match a specified condition. The $pull operator has the form: { $pull: { <field1>: <value|condition>, <field2>: <value|condition>, ... } } To specify a <field> in an embedded document or in an array, use dot notation.

How do I use $Push in MongoDB?

If the field is absent in the document to update, $push adds the array field with the value as its element. If the field is not an array, the operation will fail. If the value is an array, $push appends the whole array as a single element. To add each element of the value separately, use the $each modifier with $push .

How do I update a nested array in MongoDB?

Update Nested Arrays in Conjunction with $[]The $[<identifier>] filtered positional operator, in conjunction with the $[] all positional operator, can be used to update nested arrays. The following updates the values that are greater than or equal to 8 in the nested grades. questions array if the associated grades.

What is $Set in MongoDB?

$set outputs documents that contain all existing fields from the input documents and newly added fields. The $set stage is an alias for $addFields. Both stages are equivalent to a $project stage that explicitly specifies all existing fields in the input documents and adds the new fields.


1 Answers

The error is pretty much what it means as you cannot act on two things of the same "path" in the same update operation. The two operators you are using do not process sequentially as you might think they do.

You can do this with as "sequential" as you can possibly get with the "bulk" operations API or other form of "bulk" update though. Within reason of course, and also in reverse:

var bulk = db.coll.initializeOrderedBulkOp(); bulk.find({ "tags": 1 }).updateOne({ "$addToSet": { "tags":  2 } }); bulk.find({ "tags": 1 }).updateOne({ "$pull": { "tags": 1 } });  bulk.execute(); 

Not a guarantee that nothing else will try to modify,but it is as close as you will currently get.

Also see the raw "update" command with multiple documents.

like image 141
Neil Lunn Avatar answered Sep 28 '22 12:09

Neil Lunn