-
Type:
New Feature
-
Resolution: Unresolved
-
Priority:
Major - P3
-
None
-
Affects Version/s: None
-
Query Execution
-
None
-
3
-
None
-
None
-
None
-
None
-
None
-
None
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}.