/** * Tests the express code path, which bypasses regular query planning and execution, for writes. * Verifies some basic eligibility restrictions such as match expression shape and index options, * and checks the query results. * @tags: [ * requires_fcv_81, * requires_non_retryable_commands, * requires_non_retryable_writes, * requires_getmore, * ] */ import {assertArrayEq} from "jstests/aggregation/extras/utils.js"; import {isExpress} from "jstests/libs/query/analyze_plan.js"; const collName = "express_write_coll"; const coll = db.getCollection(collName); const docs = [ {_id: 0, a: 0}, {_id: "str", a: 1}, ]; function runExpressTest({command, expectedDocs, usesExpress}) { // Reset the collection docs. assert.commandWorked(coll.remove({})); assert.commandWorked(coll.insert(docs)); // Run the command to make sure it succeeds. assert.commandWorked(db.runCommand(command)); assertArrayEq({ actual: coll.find().toArray(), expected: expectedDocs, extraErrorMsg: "Result set comparison failed for command: " + tojson(command), }); // Reset the collection docs then run explain. assert.commandWorked(coll.remove({})); assert.commandWorked(coll.insert(docs)); const explain = assert.commandWorked(db.runCommand({explain: command, verbosity: "executionStats"})); assert.eq( usesExpress, isExpress(db, explain), "Expected the query to " + (usesExpress ? "" : "not ") + "use express: " + tojson(explain), ); } coll.drop(); // Cannot use express path when predicate is not a single equality or when a projection is present. runExpressTest({ command: {delete: collName, deletes: [{q: {_id: 0, a: 0}, limit: 0}]}, usesExpress: false, expectedDocs: [docs[1]], }); runExpressTest({ command: {delete: collName, deletes: [{q: {_id: 0, a: 0}, limit: 1}]}, usesExpress: false, expectedDocs: [docs[1]], }); runExpressTest({ command: {findAndModify: collName, query: {_id: "str", a: 1}, update: [{$set: {c: 1}}]}, usesExpress: false, expectedDocs: [docs[0], {_id: "str", a: 1, c: 1}], }); runExpressTest({ command: {findAndModify: collName, query: {_id: 0}, remove: true, fields: {_id: 1, a: 1}}, usesExpress: false, expectedDocs: [docs[1]], }); runExpressTest({ command: { findAndModify: collName, query: {_id: "str"}, update: {$set: {c: 1}}, fields: {_id: 1, a: 1, c: 1}, }, usesExpress: false, expectedDocs: [docs[0], {_id: "str", a: 1, c: 1}], }); runExpressTest({ command: {update: collName, updates: [{q: {_id: "str", a: 1}, u: {$set: {c: 1}}}]}, usesExpress: false, expectedDocs: [docs[0], {_id: "str", a: 1, c: 1}], }); // Cannot use express path when a hint is specified. assert.commandWorked(coll.createIndex({a: 1})); runExpressTest({ command: {delete: collName, deletes: [{q: {_id: 0}, limit: 0, hint: {a: 1}}]}, usesExpress: false, expectedDocs: [docs[1]], }); runExpressTest({ command: {findAndModify: collName, query: {_id: "str"}, update: [{$set: {c: 1}}], hint: {a: 1}}, usesExpress: false, expectedDocs: [docs[0], {_id: "str", a: 1, c: 1}], }); runExpressTest({ command: {update: collName, updates: [{q: {_id: "str"}, u: {$set: {c: 1}}, hint: {a: 1}}]}, usesExpress: false, expectedDocs: [docs[0], {_id: "str", a: 1, c: 1}], }); coll.dropIndexes(); // Can use express path use for delete commands when the predicate is a single equality on _id, // regardless of the 'limit' value. runExpressTest({ command: {delete: collName, deletes: [{q: {_id: 0}, limit: 0}]}, usesExpress: true, expectedDocs: [docs[1]], }); runExpressTest({ command: {delete: collName, deletes: [{q: {_id: 0}, limit: 1}]}, usesExpress: true, expectedDocs: [docs[1]], }); runExpressTest({ command: {delete: collName, deletes: [{q: {_id: "str"}, limit: 0}]}, usesExpress: true, expectedDocs: [docs[0]], }); // Same, but with query shape {_id: {$eq: }}. runExpressTest({ command: {delete: collName, deletes: [{q: {_id: {$eq: 0}}, limit: 0}]}, usesExpress: true, expectedDocs: [docs[1]], }); runExpressTest({ command: {delete: collName, deletes: [{q: {_id: {$eq: 0}}, limit: 1}]}, usesExpress: true, expectedDocs: [docs[1]], }); runExpressTest({ command: {delete: collName, deletes: [{q: {_id: {$eq: "str"}}, limit: 0}]}, usesExpress: true, expectedDocs: [docs[0]], }); // Can use express path use for findAndModify commands when the predicate is a single equality on // _id. This is true whether the findAndModify represents an update or a delete. runExpressTest({ command: {findAndModify: collName, query: {_id: "str"}, update: [{$set: {c: 1}}]}, usesExpress: true, expectedDocs: [docs[0], {_id: "str", a: 1, c: 1}], }); runExpressTest({ command: {findAndModify: collName, query: {_id: 0}, update: [{$set: {c: 1}}]}, usesExpress: true, expectedDocs: [{_id: 0, a: 0, c: 1}, docs[1]], }); runExpressTest({ command: {findAndModify: collName, query: {_id: 0}, remove: true}, usesExpress: true, expectedDocs: [docs[1]], }); // Same, but with query shape {_id: {$eq: }}. runExpressTest({ command: {findAndModify: collName, query: {_id: {$eq: "str"}}, update: [{$set: {c: 1}}]}, usesExpress: true, expectedDocs: [docs[0], {_id: "str", a: 1, c: 1}], }); runExpressTest({ command: {findAndModify: collName, query: {_id: {$eq: 0}}, update: [{$set: {c: 1}}]}, usesExpress: true, expectedDocs: [{_id: 0, a: 0, c: 1}, docs[1]], }); runExpressTest({ command: {findAndModify: collName, query: {_id: {$eq: 0}}, remove: true}, usesExpress: true, expectedDocs: [docs[1]], }); // Can use express path use for update commands when the predicate is a single equality on _id. runExpressTest({ command: {update: collName, updates: [{q: {_id: "str"}, u: {$set: {c: 1}}}]}, usesExpress: true, expectedDocs: [docs[0], {_id: "str", a: 1, c: 1}], }); runExpressTest({ command: {update: collName, updates: [{q: {_id: 0}, u: {$set: {c: 1}}}]}, usesExpress: true, expectedDocs: [{_id: 0, a: 0, c: 1}, docs[1]], }); // Same, but with query shape {_id: {$eq: }}. runExpressTest({ command: {update: collName, updates: [{q: {_id: {$eq: "str"}}, u: {$set: {c: 1}}}]}, usesExpress: true, expectedDocs: [docs[0], {_id: "str", a: 1, c: 1}], }); runExpressTest({ command: {update: collName, updates: [{q: {_id: {$eq: 0}}, u: {$set: {c: 1}}}]}, usesExpress: true, expectedDocs: [{_id: 0, a: 0, c: 1}, docs[1]], }); docs.push({_id: 2, arr: [99, 100, 101]}); runExpressTest({ command: { update: collName, updates: [ { q: {_id: 2}, u: {$set: {"arr.$[element]": 100}}, arrayFilters: [{"element": {$gte: 100}}], }, ], }, usesExpress: true, expectedDocs: [docs[0], docs[1], {_id: 2, arr: [99, 100, 100]}], }); // Same, but with query shape {_id: {$eq: }}. runExpressTest({ command: { update: collName, updates: [ { q: {_id: {$eq: 2}}, u: {$set: {"arr.$[element]": 100}}, arrayFilters: [{"element": {$gte: 100}}], }, ], }, usesExpress: true, expectedDocs: [docs[0], docs[1], {_id: 2, arr: [99, 100, 100]}], });