-
Type: Bug
-
Resolution: Done
-
Priority: Major - P3
-
None
-
Affects Version/s: 2.5.4
-
Component/s: Write Ops
-
None
-
ALL
tl;dr:
There is no consistent way to upsert an identifier-only document between 2.4.x and 2.5.x. Allowing modifiers in a newObj to be an empty BSON object would help.
I noticed the following while testing Doctrine ODM against 2.5.x. In 2.4.x and earlier versions, I believe there was only a single way to upsert a document that only contained an identifier field:
> db.foo.update({_id:1}, {$set: {}}, true); db.getLastErrorObj(); { "updatedExisting" : false, "n" : 1, "connectionId" : 1, "err" : null, "ok" : 1 } > db.foo.update({_id:2}, {}, true); db.getLastErrorObj(); { "updatedExisting" : false, "upserted" : ObjectId("52cb12553ad84dc22b80c72f"), "n" : 1, "connectionId" : 1, "err" : null, "ok" : 1 } > db.foo.update({_id:3}, {$set: {_id:3}}, true); db.getLastErrorObj(); { "err" : "Mod on _id not allowed", "code" : 10148, "n" : 0, "connectionId" : 1, "ok" : 1 } > db.foo.find() { "_id" : 1 } { "_id" : ObjectId("52cb12553ad84dc22b80c72f") }
Using an empty object for the newObj argument results in the upsert ignoring the client-provided _id. $set cannot be used on _id, even if that would technically be OK for an upsert. $setOnInsert would make more sense, but it also doesn't work – it's also 2.4+ only, so I wouldn't rely on it for essential ODM logic.
In 2.5.x, the one working method from 2.4.x no longer works. The two methods that didn't work in 2.4.x do work in 2.5.x:
> db.foo.update({_id:1}, {$set: {}}, true); db.getLastErrorObj(); { "err" : "'$set' is empty. You must specify a field like so: {$mod: {<field>: ...}}", "code" : 16840, "n" : 0, "connectionId" : 2, "ok" : 1 } > db.foo.update({_id:2}, {}, true); db.getLastErrorObj(); { "updatedExisting" : false, "upserted" : 2, "n" : 1, "connectionId" : 2, "syncMillis" : 0, "writtenTo" : null, "err" : null, "ok" : 1 } > db.foo.update({_id:3}, {$set: {_id:3}}, true); db.getLastErrorObj(); { "updatedExisting" : false, "upserted" : 3, "n" : 1, "connectionId" : 2, "syncMillis" : 0, "writtenTo" : null, "err" : null, "ok" : 1 } > db.foo.find() { "_id" : 2 } { "_id" : 3 }
The strict validation that makes the 2.4.x solution no longer work looks to have been introduced in this commit for SERVER-7175.
- is duplicated by
-
SERVER-13884 $set: {} is now rejected by the update framework, but worked as a noop prior to 2.6
- Closed
- is related to
-
SERVER-7175 Build basic update() driver functionality
- Closed
- related to
-
SERVER-13688 Picky errors from 2.6 are needlessly backwards incompatible
- Closed
-
SERVER-13883 findAndModify() cannot take an empty update object, but update() can
- Closed
- links to