[SERVER-44615] Allow upsert when specifying dotted sub-paths of _id in query predicate Created: 13/Nov/19  Updated: 06/Dec/22

Status: Backlog
Project: Core Server
Component/s: Querying, Write Ops
Affects Version/s: None
Fix Version/s: None

Type: New Feature Priority: Major - P3
Reporter: Charlie Swanson Assignee: Backlog - Query Execution
Resolution: Unresolved Votes: 0
Labels: qexec-team
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Assigned Teams:
Query Execution
Participants:

 Description   

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


Generated at Thu Feb 08 05:06:29 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.