[SERVER-80009] Update targeting logic on mongos for sharded collections does not support use of per-statement constants in query Created: 15/Aug/23  Updated: 06/Oct/23

Status: Needs Scheduling
Project: Core Server
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Kaitlin Mahar Assignee: Backlog - Query Execution
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Assigned Teams:
Query Execution
Operating System: ALL
Participants:

 Description   

Referencing per-statement c values in the q field for an update works on mongod but does not work on mongos when the collection is sharded. E.g.

db.runCommand({
    update: 'coll',
    updates: [{
        q: {$expr: {$eq: ["$skey", "$$targetKey"]}},
        u: [{'$set': {skey: '$$replacedKey'}}],
        c: {targetKey: 'MongoDB', replacedKey: 'MongoDB2'}
    }]
});

Gives a response with a write error:

{
"index" : 0,
"code" : 17276,
 "errmsg" : "Could not parse update query { $expr: { $eq: [ \"$skey\", \"$$targetKey\" ] } } :: caused by :: Use of undefined variable: targetKey"
 }

Additionally, the bulkWrite command being added in PM-1452 inherits the limitation for its per-statement constants as bulkWrite shares the same targeting logic for updates. If/when this is fixed, we should ensure the fix also works for updates in the bulkWrite command.

The issue is that we fail to canonicalize the update's query field here because the parsing logic does not have access to the constants. A fix might involve updating the logic so that the constants are passed via the ExpressionContext there, similar to what is done for the command-level let values.



 Comments   
Comment by Jason Zhang [ 06/Oct/23 ]

import {
    WriteWithoutShardKeyTestUtil
} from "jstests/sharding/updateOne_without_shard_key/libs/write_without_shard_key_test_util.js";
 
const dbName = "testDb";
const collName = "testColl";
const nss = dbName + "." + collName;
const splitPoint = 0;
 
var st = new ShardingTest({})
 
// Helper to split a sharded collection range into 2 chunks and move one of the chunks to another
// shard.
WriteWithoutShardKeyTestUtil.setupShardedCollection(
    st, nss, {x: 1}, [{x: splitPoint}], [{query: {x: splitPoint}, shard: st.shard1.shardName}]);
 
let cmdObj = {
    update: collName,
    updates: [{q: {$expr: {$eq: ["$x", "$$myVal"]}}, u: [{$set: {z: 3}}], c: {myVal: 1}}],
};
 
// This fails with "Use of undefined variable: myVal".
assert.commandWorked(st.s.getDB(dbName).runCommand(cmdObj));
 
st.stop();

Just adding a repro script just in case. In order to trigger the error, the collection must be sharded across multiple shards.

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