|
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}.
|