diff options
author | Katherine Wu <katherine.wu@mongodb.com> | 2021-06-10 13:49:19 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-06-14 21:38:33 +0000 |
commit | 19572bcc17bf07c391a2248e0dd52bc08d207fcd (patch) | |
tree | 61dbdf1ac44a2b3be8657b29b2709ebc738faabb | |
parent | 431106074ec36920816a002296f10d44fdf9d971 (diff) | |
download | mongo-19572bcc17bf07c391a2248e0dd52bc08d207fcd.tar.gz |
SERVER-57403 Serialize 'let' variables by wrapping with $literal
-rw-r--r-- | jstests/core/command_let_variables.js | 7 | ||||
-rw-r--r-- | jstests/noPassthroughWithMongod/command_let_variables_merge_only.js | 33 | ||||
-rw-r--r-- | src/mongo/db/pipeline/variables.cpp | 4 |
3 files changed, 41 insertions, 3 deletions
diff --git a/jstests/core/command_let_variables.js b/jstests/core/command_let_variables.js index 208a0801530..6a3de698291 100644 --- a/jstests/core/command_let_variables.js +++ b/jstests/core/command_let_variables.js @@ -536,4 +536,11 @@ assert.between(0, result, 1); const deduped = [...new Set(values)]; assert.eq(1, deduped.length, `Expected all identical values: ${deduped}`); } + +// Test that expressions wrapped with $literal are serialized correctly when run in sharded cluster +// environments. +result = coll.aggregate([{$match: {$expr: {$eq: ["$_id", 2]}}}, {$project: {a: "$$b"}}], + {let : {b: {$literal: "$notAFieldPath"}}}) + .toArray(); +assert.eq(result, [{_id: 2, a: "$notAFieldPath"}]); }()); diff --git a/jstests/noPassthroughWithMongod/command_let_variables_merge_only.js b/jstests/noPassthroughWithMongod/command_let_variables_merge_only.js index b6d5ceddbbf..ab913e01888 100644 --- a/jstests/noPassthroughWithMongod/command_let_variables_merge_only.js +++ b/jstests/noPassthroughWithMongod/command_let_variables_merge_only.js @@ -1,7 +1,7 @@ // Tests that the aggregate command can use command-level let variables with $merge. Note $merge // tests must be run in a noPassthrough suite so the other operators are exercised in // jstests/core/command_let_variables.js. -// @tags: [assumes_against_mongod_not_mongos, requires_fcv46] +// @tags: [requires_fcv46] (function() { "use strict"; @@ -125,4 +125,35 @@ assert.commandWorked(db.runCommand({ let : {variable: "OUTER"} })); assert.eq(targetColl.aggregate({$match: {$expr: {$eq: ["$var", "INNER"]}}}).toArray().length, 1); + +// Test that expressions wrapped with $literal are serialized correctly in combination with +// pipelines containing $merge. +prepMergeTargetColl(); +assert.commandWorked(db.runCommand({ + aggregate: coll.getName(), + pipeline: [{$project: {var : "$$variable"}}, {$merge: {into: targetColl.getName()}}], + let : {variable: {$literal: "$notAFieldPath"}}, + cursor: {} +})); +assert.eq(targetColl.aggregate({$match: {$expr: {$eq: ["$var", {$literal: "$notAFieldPath"}]}}}) + .toArray() + .length, + 4); + +prepMergeTargetColl(); +assert.commandWorked(db.runCommand({ + aggregate: coll.getName(), + pipeline: [{ + $merge: { + into: targetColl.getName(), + let : {variable: {$literal: "$notAFieldPath"}}, + whenMatched: [{$addFields: {"var": "$$variable"}}] + } + }], + cursor: {}, +})); +assert.eq(targetColl.aggregate({$match: {$expr: {$eq: ["$var", {$literal: "$notAFieldPath"}]}}}) + .toArray() + .length, + 1); }()); diff --git a/src/mongo/db/pipeline/variables.cpp b/src/mongo/db/pipeline/variables.cpp index 8cabf0f3c52..6adc0e280c1 100644 --- a/src/mongo/db/pipeline/variables.cpp +++ b/src/mongo/db/pipeline/variables.cpp @@ -350,7 +350,7 @@ BSONObj VariablesParseState::serialize(const Variables& vars) const { auto bob = BSONObjBuilder{}; for (auto&& [var_name, id] : _variables) if (vars.hasValue(id)) - bob << var_name << vars.getValue(id); + bob << var_name << Value(DOC("$literal" << vars.getValue(id))); // System variables have to be added separately since the variable IDs are reserved and not // allocated like normal variables, and so not present in '_variables'. @@ -363,7 +363,7 @@ std::pair<LegacyRuntimeConstants, BSONObj> VariablesParseState::transitionalComp auto bob = BSONObjBuilder{}; for (auto&& [var_name, id] : _variables) if (vars.hasValue(id)) - bob << var_name << vars.getValue(id); + bob << var_name << Value(DOC("$literal" << vars.getValue(id))); return {vars.transitionalExtractRuntimeConstants(), bob.obj()}; } |