Uploaded image for project: 'Core Server'
  1. Core Server
  2. SERVER-12266

Update no longer allows empty modifier objects

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major - P3
    • Resolution: Works as Designed
    • Affects Version/s: 2.5.4
    • Fix Version/s: None
    • Component/s: Write Ops
    • Labels:
      None
    • Operating System:
      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

            Activity

              People

              • Votes:
                0 Vote for this issue
                Watchers:
                14 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: