summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSally McNichols <sally.mcnichols@mongodb.com>2016-06-30 14:13:27 -0400
committerSally McNichols <sally.mcnichols@mongodb.com>2016-06-30 14:13:27 -0400
commitf3919fcaa84bc10597df41d250a7493e2b378bba (patch)
tree0667329bfadabea0cd789f9d2e1ce336de654b84
parentcce13607bbd38814446e48d3433bbcf7acb26690 (diff)
downloadmongo-f3919fcaa84bc10597df41d250a7493e2b378bba.tar.gz
SERVER-24302 Make "as" option of $filter and $map default to "this"
-rw-r--r--jstests/aggregation/bugs/server17943.js22
-rw-r--r--jstests/aggregation/bugs/server9841.js5
-rw-r--r--src/mongo/db/pipeline/expression.cpp12
3 files changed, 30 insertions, 9 deletions
diff --git a/jstests/aggregation/bugs/server17943.js b/jstests/aggregation/bugs/server17943.js
index 7036a16b940..35d67d4fe20 100644
--- a/jstests/aggregation/bugs/server17943.js
+++ b/jstests/aggregation/bugs/server17943.js
@@ -31,6 +31,20 @@ load('jstests/aggregation/extras/utils.js');
var results = coll.aggregate([{$project: {b: {$filter: filterDoc}}}]).toArray();
assert.eq(results, expectedResults);
+ // create filter that uses the default variable name in 'cond'
+ filterDoc = {input: '$a', cond: {$eq: [2, '$$this']}};
+ expectedResults = [
+ {_id: 0, b: [2]},
+ {_id: 1, b: [2]},
+ {_id: 2, b: []},
+ {_id: 3, b: []},
+ {_id: 4, b: null},
+ {_id: 5, b: null},
+ {_id: 6, b: null},
+ ];
+ results = coll.aggregate([{$project: {b: {$filter: filterDoc}}}]).toArray();
+ assert.eq(results, expectedResults);
+
// Invalid filter expressions.
// Insert a document so that the initial cursor doesn't immediately return EOF.
@@ -48,10 +62,6 @@ load('jstests/aggregation/extras/utils.js');
filterDoc = {as: 'x', cond: true};
assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 28648);
- // Missing 'as'.
- filterDoc = {input: '$a', cond: true};
- assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 28649);
-
// Missing 'cond'.
filterDoc = {input: '$a', as: 'x'};
assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 28650);
@@ -64,6 +74,10 @@ load('jstests/aggregation/extras/utils.js');
filterDoc = {input: 'string', as: 'x', cond: true};
assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 28651);
+ // 'cond' uses undefined variable name.
+ filterDoc = {input: '$a', cond: {$eq: [1, '$$var']}};
+ assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 17276);
+
coll.drop();
assert.writeOK(coll.insert({a: 'string'}));
filterDoc = {input: '$a', as: 'x', cond: true};
diff --git a/jstests/aggregation/bugs/server9841.js b/jstests/aggregation/bugs/server9841.js
index 28e6037caf1..0f670692adb 100644
--- a/jstests/aggregation/bugs/server9841.js
+++ b/jstests/aggregation/bugs/server9841.js
@@ -18,6 +18,7 @@ function test(expression, expected) {
test({$map: {input: "$simple", as: "var", in : '$$var'}}, [1, 2, 3, 4]);
test({$map: {input: "$simple", as: "var", in : {$add: [10, '$$var']}}}, [11, 12, 13, 14]);
+test({$map: {input: "$simple", in : '$$this'}}, [1, 2, 3, 4]);
test({$map: {input: "$nested", as: "var", in : '$$var.a'}}, [1, 2]);
test({$map: {input: "$nested", as: "CURRENT", in : '$a'}}, [1, 2]);
@@ -37,5 +38,7 @@ assertErrorCode(t, {$project: {a: {$map: {input: "$notArray", as: "var", in : '$
assertErrorCode(
t, {$project: {a: {$map: {x: 1, input: "$simple", as: "var", in : '$$var'}}}}, 16879);
assertErrorCode(t, {$project: {a: {$map: {as: "var", in : '$$var'}}}}, 16880);
-assertErrorCode(t, {$project: {a: {$map: {input: "$simple", in : '$$var'}}}}, 16881);
assertErrorCode(t, {$project: {a: {$map: {input: "$simple", as: "var"}}}}, 16882);
+
+// 'in' uses undefined variable name.
+assertErrorCode(t, {$project: {a: {$map: {input: "$simple", in : '$$var'}}}}, 17276);
diff --git a/src/mongo/db/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp
index ad958e837a1..e35adeefe9b 100644
--- a/src/mongo/db/pipeline/expression.cpp
+++ b/src/mongo/db/pipeline/expression.cpp
@@ -1379,7 +1379,6 @@ intrusive_ptr<Expression> ExpressionFilter::parse(BSONElement expr,
}
uassert(28648, "Missing 'input' parameter to $filter", !inputElem.eoo());
- uassert(28649, "Missing 'as' parameter to $filter", !asElem.eoo());
uassert(28650, "Missing 'cond' parameter to $filter", !condElem.eoo());
// Parse "input", only has outer variables.
@@ -1387,7 +1386,10 @@ intrusive_ptr<Expression> ExpressionFilter::parse(BSONElement expr,
// Parse "as".
VariablesParseState vpsSub(vpsIn); // vpsSub gets our variable, vpsIn doesn't.
- string varName = asElem.str();
+
+ // If "as" is not specified, then use "this" by default.
+ auto varName = asElem.eoo() ? "this" : asElem.str();
+
Variables::uassertValidNameForUserWrite(varName);
Variables::Id varId = vpsSub.defineVariable(varName);
@@ -1595,7 +1597,6 @@ intrusive_ptr<Expression> ExpressionMap::parse(BSONElement expr, const Variables
}
uassert(16880, "Missing 'input' parameter to $map", !inputElem.eoo());
- uassert(16881, "Missing 'as' parameter to $map", !asElem.eoo());
uassert(16882, "Missing 'in' parameter to $map", !inElem.eoo());
// parse "input"
@@ -1603,7 +1604,10 @@ intrusive_ptr<Expression> ExpressionMap::parse(BSONElement expr, const Variables
// parse "as"
VariablesParseState vpsSub(vpsIn); // vpsSub gets our vars, vpsIn doesn't.
- string varName = asElem.str();
+
+ // If "as" is not specified, then use "this" by default.
+ auto varName = asElem.eoo() ? "this" : asElem.str();
+
Variables::uassertValidNameForUserWrite(varName);
Variables::Id varId = vpsSub.defineVariable(varName);