-
Type: Task
-
Resolution: Done
-
Priority: Major - P3
-
None
-
Affects Version/s: None
-
Component/s: Rel Notes
-
Labels:None
In versions prior to 3.4, it was possible to issue a single-element $in query with {upsert: true} as shown below:
> db.c.drop() false > db.c.update({a: {$in: [1]}}, {$addToSet: {a: 2}}, {upsert: true}) WriteResult({ "nMatched" : 0, "nUpserted" : 1, "nModified" : 0, "_id" : ObjectId("58bdb00eb39e8f87607e9222") }) > db.c.find() { "_id" : ObjectId("58bdb00eb39e8f87607e9222"), "a" : [ 2 ] }
This is no longer possible in 3.4:
> db.c.drop() true > db.c.update({a: {$in: [1]}}, {$addToSet: {a: 2}}, {upsert: true}) WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0, "writeError" : { "code" : 16836, "errmsg" : "Cannot apply $addToSet to a non-array field. Field named 'a' has a non-array type double in the document INVALID-MUTABLE-ELEMENT" } })
This is a breaking change which should be added to the section on "Compatibility Changes in MongoDB 3.4": https://docs.mongodb.com/manual/release-notes/3.4-compatibility/.
The reasoning is that single-element $in predicates are logically equivalent to equality predicates. Therefore, like any equality predicate, a single-element $in should seed the document being inserted when an upsert matches no documents. In the example above, the predicate {a: {$in: [1]}} seeds the document to insert with the fields {a: 1}. We then attempt to apply the $addToSet predicate to this document, which is invalid since field a does not contain an array. Users which want this behavior must wrap $in inside an $elemMatch:
> db.c.drop(); true > db.c.update({a: {$elemMatch: {$in: [2]}}}, {$addToSet: {a: 3}}, {upsert: true}); WriteResult({ "nMatched" : 0, "nUpserted" : 1, "nModified" : 0, "_id" : ObjectId("58bda2706b1609466de3d5dc") }) > db.c.find(); { "_id" : ObjectId("58bda2706b1609466de3d5dc"), "a" : [ 3 ] }
See SERVER-27707 for further details. I'd be happy to review a draft of the new documentation.
- documents
-
SERVER-27707 findAndModify breaks when I use the query operator "$in" and the update operator "$addToSet" on the same field.
- Closed