Reputation: 489
Please see mongo query below. I want to be able to update a document if it meets the conditions. I want to create a new document if x or y arent met but i dont want to create a new document if x and y are met but z has a value
collection.update({ x : 1, y : 2, z : {$exists : false} }, {field_to_update : update}, { upsert :true })
Upvotes: 2
Views: 2943
Reputation: 489
The solution was to create a unique compound index on the first two fields. Thanks
Upvotes: 2
Reputation: 151170
There is a "possible" way to do this, but you have to be very careful about what you are even considering here. Consider the following initial documents:
{ "x" : 1, "y" : 2, "z" : 4, "a" : 2 }
{ "x" : 1, "y" : 2, "a" : 2 }
{ "x" : 1, "y" : 2, "z" : 5, "a" : 4 }
{ "x" : 4, "y" : 2, "a": 1 }
Your basic conditions say that you want to match on "x" and "y" but only insert a new document if there is not a match on "z" for any value. Presumably though if "x" and "y" do not match then you want to insert a new document.
The main consideration here is "which" document do you want to update? There may be as shown above multiple matches to this condition, which would ideally match two of the documents here and not the document that has { "x": 1, "y": 2 }
but no value for "z". If you are okay with that as a logic principle then the following might be of use:
db.test.update(
{
"x": 1,
"y": 2,
"z": { "$exists": true },
},
{
"$set": { "a": 3 },
"$setOnInsert": { "z": 3 }
},
{
"multi": true,
"upsert": true
}
)
The important part here is the use of the $exists
operator since you don't want to modify anything that simply didn't have anything for "z" at all, you could additionally constrain that to numeric types if needed but the main point is missing the document you do not want to update.
Since you are not specifying a value of "z" to match on the query side, it is likely that you do have something you want when you "upsert", so include that in the $setOnInsert
modifier as we show what happens when the conditions do not match:
db.test.update(
{
"x": 4,
"y": 2,
"z": { "$exists": true },
},
{
"$set": { "a": 3 },
"$setOnInsert": { "z": 3 }
},
{
"multi": true,
"upsert": true
}
)
So while there was a document there with the same values for "x" and "y" as given in the statement, it does not have any value for "z" and so a new document would be inserted by the "upsert" condition. The resulting documents from the two statements now look like this:
{ "x" : 1, "y" : 2, "z" : 4, "a" : 3 }
{ "x" : 1, "y" : 2, "a" : 2 }
{ "x" : 1, "y" : 2, "z" : 5, "a" : 3 }
{ "x" : 4, "y" : 2, "a" : 1 }
{ "x" : 4, "y" : 2, "a" : 3, "z" : 3 }
As long as you can live with the consideration that "any value" for "z" can easily result in multiple documents being updated, then this is the way to handle the "upsert" conditions that you want.
Upvotes: 1