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

Allow upsert when specifying dotted sub-paths of _id in query predicate

    • Type: Icon: New Feature New Feature
    • Resolution: Unresolved
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: None
    • Component/s: Querying, Write Ops
    • Labels:
    • Query Execution

      bernard.gorman and I had a long discussion about this when working on SERVER-43860. Today, with a shard key pattern of {"bar.x": 1, "bar.y": 1} you are able to do an upsert in either of the following ways:

      mongos> db.bar.replaceOne({"bar": {x: 3, "y": 3}}, {unrelated: 2}, {upsert: true})
      {
          "acknowledged" : true,
          "matchedCount" : 0,
          "modifiedCount" : 0,
          "upsertedId" : ObjectId("5dcc733e983b13bb23055039")
      }
      mongos> db.bar.replaceOne({"bar.x": 2, "bar.y": 5}, {unrelated: 4}, {upsert: true})
      {
          "acknowledged" : true,
          "matchedCount" : 0,
          "modifiedCount" : 0,
          "upsertedId" : ObjectId("5dcc734f983b13bb23055041")
      }
      

      However, because _id is immutable, we are not quite smart enough to allow you to perform both styles of update when your shard key is {"_id.x": 1, "_id.y": 1}. You can only perform the version which specifies the entire _id object:

      mongos> db.testing.update({_id: {x: 150, y: 150}}, {_id: {x: 150, y: 150}, updated: true}, true)
      WriteResult({
          "nMatched" : 0,
          "nUpserted" : 1,
          "nModified" : 0,
          "_id" : {
              "x" : 150,
              "y" : 150
          }
      })
      mongos> db.testing.update({"_id.x": 150, "_id.y": 150}, {_id: {x: 150, y: 150}, updated: true}, true)
      WriteResult({
          "nMatched" : 0,
          "nUpserted" : 0,
          "nModified" : 0,
          "writeError" : {
              "code" : 111,
              "errmsg" : "field at '_id' must be exactly specified, field at sub-path '_id.x'found"
          }
      })
      mongos> db.testing.update({"_id.x": 150, "_id.y": 150}, {updated: true}, true)
      WriteResult({
          "nMatched" : 0,
          "nUpserted" : 0,
          "nModified" : 0,
          "writeError" : {
              "code" : 61,
              "errmsg" : "Expected replacement document to include all shard key fields, but the following were omitted: { missingShardKeyFields: [ \"_id.x\", \"_id.y\" ] }"
          }
      })
      

      This is of course inconsistent. It also seems prudent to favor the dotted-path form of querying over the explicit object, to avoid issues like {x: 1, y: 1} not comparing equal to {y: 1, x: 1}.

            Assignee:
            backlog-query-execution [DO NOT USE] Backlog - Query Execution
            Reporter:
            charlie.swanson@mongodb.com Charlie Swanson
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated: