Details
-
Bug
-
Status: Closed
-
Major - P3
-
Resolution: Works as Designed
-
2.5.4
-
None
-
None
-
ALL
Description
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.
Attachments
Issue Links
- 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
-
-
DOCS-3479 Include update validation rules
-
- Closed
-
- links to