diff options
author | Anton Korshunov <anton.korshunov@mongodb.com> | 2019-09-24 18:09:14 +0000 |
---|---|---|
committer | evergreen <evergreen@mongodb.com> | 2019-09-24 18:09:14 +0000 |
commit | d4c306ea210d905578c2cf464a117815d6ea83b9 (patch) | |
tree | 761704b51925421326e8975625f22f9c07e0481a /src/mongo | |
parent | 8e35b7bc673e3bddf7049a44884d79ffb862a77d (diff) | |
download | mongo-d4c306ea210d905578c2cf464a117815d6ea83b9.tar.gz |
SERVER-43377 Make positional projection internal expression able to access Document pre-image
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/exec/find_projection_executor.cpp | 9 | ||||
-rw-r--r-- | src/mongo/db/exec/find_projection_executor.h | 21 | ||||
-rw-r--r-- | src/mongo/db/exec/find_projection_executor_test.cpp | 22 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_find_internal.h | 23 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression_find_internal_test.cpp | 52 | ||||
-rw-r--r-- | src/mongo/db/pipeline/parsed_aggregation_projection.h | 24 | ||||
-rw-r--r-- | src/mongo/db/pipeline/parsed_find_projection_test.cpp | 43 |
7 files changed, 157 insertions, 37 deletions
diff --git a/src/mongo/db/exec/find_projection_executor.cpp b/src/mongo/db/exec/find_projection_executor.cpp index a1855ba7e8a..098cdb93d71 100644 --- a/src/mongo/db/exec/find_projection_executor.cpp +++ b/src/mongo/db/exec/find_projection_executor.cpp @@ -156,10 +156,11 @@ Value extractArrayElement(const Value& arr, const std::string& elemIndex) { return arr[*index]; } -Document applyPositionalProjection(const Document& input, +Document applyPositionalProjection(const Document& preImage, + const Document& postImage, const MatchExpression& matchExpr, const FieldPath& path) { - MutableDocument output(input); + MutableDocument output(postImage); // Try to find the first matching array element from the 'input' document based on the condition // specified as 'matchExpr'. If such an element is found, its position within an array will be @@ -169,7 +170,7 @@ Document applyPositionalProjection(const Document& input, // invariant to make sure this is the case indeed. MatchDetails details; details.requestElemMatchKey(); - invariant(matchExpr.matchesBSON(input.toBson(), &details)); + invariant(matchExpr.matchesBSON(preImage.toBson(), &details)); // At this stage we know that the 'input' document matches against the specified condition, // but the matching array element may not be found. This can happen if the field, specified @@ -181,7 +182,7 @@ Document applyPositionalProjection(const Document& input, // found, then we will extract the matching element from this array and will store it as // the current sub-path in the 'output' document. Otherwise, just leave the 'output' // document untouched. - for (auto [ind, subDoc] = std::pair{0ULL, input}; ind < path.getPathLength(); ind++) { + for (auto [ind, subDoc] = std::pair{0ULL, postImage}; ind < path.getPathLength(); ind++) { switch (auto val = subDoc[path.getFieldName(ind)]; val.getType()) { case BSONType::Array: { // Raise an error if we found the first array on the 'path', but the matching array diff --git a/src/mongo/db/exec/find_projection_executor.h b/src/mongo/db/exec/find_projection_executor.h index 0add0908de1..c14e63f7386 100644 --- a/src/mongo/db/exec/find_projection_executor.h +++ b/src/mongo/db/exec/find_projection_executor.h @@ -43,21 +43,28 @@ namespace projection_executor { Value extractArrayElement(const Value& arr, const std::string& elemIndex); /** - * Applies a positional projection on the first array found in the 'path' on the 'input' document. - * The applied projection is returned as a Document. The 'matchExpr' specifies a condition to - * locate the first matching element in the array and must match the input document. For example, - * given: + * Applies a positional projection on the first array found in the 'path' on a projection + * 'preImage' document. The applied projection is merged with a projection 'postImage' document. + * The 'matchExpr' specifies a condition to locate the first matching element in the array and must + * match the input document. Note that the match expression must be applied to the projection + * post-image, as it may contain conditions on fields which are not included into the projection + * post-image. So, the pre-image document will be used to match an array and record a position of + * the matching element, whilst the actual result will be merged into the post-image. * - * - the 'input' document {bar: 1, foo: {bar: [1,2,6,10]}} + * For example, given: + * + * - the 'preImage' document {bar: 1, foo: {bar: [1,2,6,10]}} + * - the 'postImage' document {foo: {bar: [1,2,6,10]}} * - the 'matchExpr' condition {bar: 1, 'foo.bar': {$gte: 5}} * - and the 'path' for the positional projection of 'foo.bar' * - * The resulting document will contain the following element: {bar: 1, foo: {bar: [6]}} + * The resulting document will contain the following element: {foo: {bar: [6]}} * * Throws an AssertionException if 'matchExpr' matches the input document, but an array element * satisfying positional projection requirements cannot be found. */ -Document applyPositionalProjection(const Document& input, +Document applyPositionalProjection(const Document& preImage, + const Document& postImage, const MatchExpression& matchExpr, const FieldPath& path); /** diff --git a/src/mongo/db/exec/find_projection_executor_test.cpp b/src/mongo/db/exec/find_projection_executor_test.cpp index 32654ca050f..0282d8ca383 100644 --- a/src/mongo/db/exec/find_projection_executor_test.cpp +++ b/src/mongo/db/exec/find_projection_executor_test.cpp @@ -39,10 +39,19 @@ namespace mongo { namespace projection_executor { namespace positional_projection_tests { -auto applyPositional(const BSONObj& match, const std::string& path, const Document& input) { +/** + * Applies a find()-style positional projection at the given 'path' using 'matchSpec' to create + * a 'MatchExpression' to match an element on the first array in the 'path'. If no value for + * 'postImage' is provided, then the post-image used will be the value passed for the 'preImage'. + */ +auto applyPositional(const BSONObj& matchSpec, + const std::string& path, + const Document& preImage, + boost::optional<Document> postImage = boost::none) { boost::intrusive_ptr<ExpressionContextForTest> expCtx(new ExpressionContextForTest()); - auto matchExpr = uassertStatusOK(MatchExpressionParser::parse(match, expCtx)); - return projection_executor::applyPositionalProjection(input, *matchExpr, path); + auto matchExpr = uassertStatusOK(MatchExpressionParser::parse(matchSpec, expCtx)); + return projection_executor::applyPositionalProjection( + preImage, postImage.value_or(preImage), *matchExpr, path); } TEST(PositionalProjection, CorrectlyProjectsSimplePath) { @@ -115,6 +124,13 @@ TEST(PositionalProjection, CanMergeWithExistingFieldsInOutputDocument) { doc = Document{fromjson("{bar: 1, foo: 3}")}; ASSERT_DOCUMENT_EQ(doc, applyPositional(fromjson("{foo: 3}"), "foo", doc)); } + +TEST(PositionalProjection, AppliesMatchExpressionToPreImageAndStoresResultInPostImage) { + auto preImage = Document{fromjson("{foo: 1, bar: [1,2,6,10]}")}; + auto postImage = Document{fromjson("{bar: [1,2,6,10]}")}; + ASSERT_DOCUMENT_EQ(Document{fromjson("{bar: [6]}")}, + applyPositional(fromjson("{foo: 1, bar: 6}"), "bar", preImage, postImage)); +} } // namespace positional_projection_tests namespace elem_match_projection_tests { diff --git a/src/mongo/db/pipeline/expression_find_internal.h b/src/mongo/db/pipeline/expression_find_internal.h index 2459bcf14cb..61a696c5d9d 100644 --- a/src/mongo/db/pipeline/expression_find_internal.h +++ b/src/mongo/db/pipeline/expression_find_internal.h @@ -44,21 +44,29 @@ namespace mongo { class ExpressionInternalFindPositional final : public Expression { public: ExpressionInternalFindPositional(const boost::intrusive_ptr<ExpressionContext>& expCtx, - boost::intrusive_ptr<Expression> child, + boost::intrusive_ptr<Expression> preImageExpr, + boost::intrusive_ptr<Expression> postImageExpr, FieldPath path, const MatchExpression* matchExpr) - : Expression{expCtx, {child}}, _path{std::move(path)}, _matchExpr{matchExpr} {} + : Expression{expCtx, {preImageExpr, postImageExpr}}, + _path{std::move(path)}, + _matchExpr{matchExpr} {} Value evaluate(const Document& root, Variables* variables) const final { using namespace fmt::literals; - auto postImage = _children[0]->evaluate(root, variables); + auto preImage = _children[0]->evaluate(root, variables); + auto postImage = _children[1]->evaluate(root, variables); uassert(51255, - "Positional operator can only be applied to an object, but got {}"_format( + "Positional operator pre-image can only be an object, but got {}"_format( + typeName(preImage.getType())), + preImage.getType() == BSONType::Object); + uassert(51258, + "Positional operator post-image can only be an object, but got {}"_format( typeName(postImage.getType())), postImage.getType() == BSONType::Object); return Value{projection_executor::applyPositionalProjection( - postImage.getDocument(), *_matchExpr, _path)}; + preImage.getDocument(), postImage.getDocument(), *_matchExpr, _path)}; } void acceptVisitor(ExpressionVisitor* visitor) final { @@ -79,6 +87,7 @@ public: protected: void _doAddDependencies(DepsTracker* deps) const final { _children[0]->addDependencies(deps); + _children[1]->addDependencies(deps); deps->needWholeDocument = true; _matchExpr->addDependencies(deps); } @@ -97,11 +106,11 @@ private: class ExpressionInternalFindSlice final : public Expression { public: ExpressionInternalFindSlice(const boost::intrusive_ptr<ExpressionContext>& expCtx, - boost::intrusive_ptr<Expression> child, + boost::intrusive_ptr<Expression> postImageExpr, FieldPath path, boost::optional<int> skip, int limit) - : Expression{expCtx, {child}}, _path{std::move(path)}, _skip{skip}, _limit{limit} {} + : Expression{expCtx, {postImageExpr}}, _path{std::move(path)}, _skip{skip}, _limit{limit} {} Value evaluate(const Document& root, Variables* variables) const final { using namespace fmt::literals; diff --git a/src/mongo/db/pipeline/expression_find_internal_test.cpp b/src/mongo/db/pipeline/expression_find_internal_test.cpp index 453a37c7055..9fff474201c 100644 --- a/src/mongo/db/pipeline/expression_find_internal_test.cpp +++ b/src/mongo/db/pipeline/expression_find_internal_test.cpp @@ -36,12 +36,25 @@ #include "mongo/unittest/unittest.h" namespace mongo::expression_internal_tests { +constexpr auto kProjectionPostImageVarName = + parsed_aggregation_projection::ParsedAggregationProjection::kProjectionPostImageVarName; + +auto defineAndSetProjectionPostImageVariable(boost::intrusive_ptr<ExpressionContext> expCtx, + Value postImage) { + auto& vps = expCtx->variablesParseState; + auto varId = vps.defineVariable(kProjectionPostImageVarName); + expCtx->variables.setValue(varId, postImage); + return varId; +} + class ExpressionInternalFindPositionalTest : public AggregationContextFixture { protected: auto createExpression(const MatchExpression* matchExpr, const std::string& path) { auto expr = make_intrusive<ExpressionInternalFindPositional>( getExpCtx(), ExpressionFieldPath::parse(getExpCtx(), "$$ROOT", getExpCtx()->variablesParseState), + ExpressionFieldPath::parse( + getExpCtx(), "$$" + kProjectionPostImageVarName, getExpCtx()->variablesParseState), path, matchExpr); return expr; @@ -53,7 +66,8 @@ protected: auto createExpression(const std::string& path, boost::optional<int> skip, int limit) { auto expr = make_intrusive<ExpressionInternalFindSlice>( getExpCtx(), - ExpressionFieldPath::parse(getExpCtx(), "$$ROOT", getExpCtx()->variablesParseState), + ExpressionFieldPath::parse( + getExpCtx(), "$$" + kProjectionPostImageVarName, getExpCtx()->variablesParseState), path, skip, limit); @@ -72,7 +86,10 @@ protected: } }; -TEST_F(ExpressionInternalFindPositionalTest, AppliesProjectionToRootDocument) { +TEST_F(ExpressionInternalFindPositionalTest, AppliesProjectionToPostImage) { + defineAndSetProjectionPostImageVariable(getExpCtx(), + Value{fromjson("{bar: 1, foo: [1,2,6,10]}")}); + auto matchSpec = fromjson("{bar: 1, foo: {$gte: 5}}"); auto matchExpr = uassertStatusOK(MatchExpressionParser::parse(matchSpec, getExpCtx())); auto expr = createExpression(matchExpr.get(), "foo"); @@ -84,6 +101,8 @@ TEST_F(ExpressionInternalFindPositionalTest, AppliesProjectionToRootDocument) { } TEST_F(ExpressionInternalFindPositionalTest, RecordsProjectionDependencies) { + auto varId = defineAndSetProjectionPostImageVariable( + getExpCtx(), Value{fromjson("{bar: 1, foo: [1,2,6,10]}")}); auto matchSpec = fromjson("{bar: 1, foo: {$gte: 5}}"); auto matchExpr = uassertStatusOK(MatchExpressionParser::parse(matchSpec, getExpCtx())); auto expr = createExpression(matchExpr.get(), "foo"); @@ -94,11 +113,15 @@ TEST_F(ExpressionInternalFindPositionalTest, RecordsProjectionDependencies) { ASSERT_EQ(deps.fields.size(), 2UL); ASSERT_EQ(deps.fields.count("bar"), 1UL); ASSERT_EQ(deps.fields.count("foo"), 1UL); - ASSERT_EQ(deps.vars.size(), 0UL); - ASSERT(deps.needWholeDocument); + ASSERT_EQ(deps.vars.size(), 1UL); + ASSERT_EQ(deps.vars.count(varId), 1UL); + ASSERT_TRUE(deps.needWholeDocument); } TEST_F(ExpressionInternalFindPositionalTest, AddsArrayUndottedPathToComputedPaths) { + defineAndSetProjectionPostImageVariable(getExpCtx(), + Value{fromjson("{bar: 1, foo: [1,2,6,10]}")}); + auto matchSpec = fromjson("{bar: 1, foo: {$gte: 5}}"); auto matchExpr = uassertStatusOK(MatchExpressionParser::parse(matchSpec, getExpCtx())); auto expr = createExpression(matchExpr.get(), "foo"); @@ -113,6 +136,9 @@ TEST_F(ExpressionInternalFindPositionalTest, AddsArrayUndottedPathToComputedPath TEST_F(ExpressionInternalFindPositionalTest, AddsOnlyTopLevelFieldOfArrayDottedPathToComputedPaths) { + defineAndSetProjectionPostImageVariable(getExpCtx(), + Value{fromjson("{bar: 1, foo: [1,2,6,10]}")}); + auto matchSpec = fromjson("{bar: 1, 'foo.bar': {$gte: 5}}"); auto matchExpr = uassertStatusOK(MatchExpressionParser::parse(matchSpec, getExpCtx())); auto expr = createExpression(matchExpr.get(), "foo.bar"); @@ -125,7 +151,10 @@ TEST_F(ExpressionInternalFindPositionalTest, ASSERT_EQ(computedPaths.paths.count("foo"), 1UL); } -TEST_F(ExpressionInternalFindSliceTest, AppliesProjectionToRootDocument) { +TEST_F(ExpressionInternalFindSliceTest, AppliesProjectionToPostImage) { + defineAndSetProjectionPostImageVariable(getExpCtx(), + Value{fromjson("{bar: 1, foo: [1,2,6,10]}")}); + auto expr = createExpression("foo", 1, 2); ASSERT_DOCUMENT_EQ( @@ -135,17 +164,23 @@ TEST_F(ExpressionInternalFindSliceTest, AppliesProjectionToRootDocument) { } TEST_F(ExpressionInternalFindSliceTest, RecordsProjectionDependencies) { + auto varId = defineAndSetProjectionPostImageVariable( + getExpCtx(), Value{fromjson("{bar: 1, foo: [1,2,6,10]}")}); auto expr = createExpression("foo", 1, 2); DepsTracker deps; expr->addDependencies(&deps); ASSERT_EQ(deps.fields.size(), 0UL); - ASSERT_EQ(deps.vars.size(), 0UL); - ASSERT(deps.needWholeDocument); + ASSERT_EQ(deps.vars.size(), 1UL); + ASSERT_EQ(deps.vars.count(varId), 1UL); + ASSERT_TRUE(deps.needWholeDocument); } TEST_F(ExpressionInternalFindSliceTest, AddsArrayUndottedPathToComputedPaths) { + defineAndSetProjectionPostImageVariable(getExpCtx(), + Value{fromjson("{bar: 1, foo: [1,2,6,10]}")}); + auto expr = createExpression("foo", 1, 2); DepsTracker deps; @@ -157,6 +192,9 @@ TEST_F(ExpressionInternalFindSliceTest, AddsArrayUndottedPathToComputedPaths) { } TEST_F(ExpressionInternalFindSliceTest, AddsTopLevelFieldOfArrayDottedPathToComputedPaths) { + defineAndSetProjectionPostImageVariable(getExpCtx(), + Value{fromjson("{bar: 1, foo: [1,2,6,10]}")}); + auto expr = createExpression("foo.bar", 1, 2); DepsTracker deps; diff --git a/src/mongo/db/pipeline/parsed_aggregation_projection.h b/src/mongo/db/pipeline/parsed_aggregation_projection.h index d1ee17056cd..e7ac7d2ab95 100644 --- a/src/mongo/db/pipeline/parsed_aggregation_projection.h +++ b/src/mongo/db/pipeline/parsed_aggregation_projection.h @@ -144,6 +144,12 @@ private: class ParsedAggregationProjection : public TransformerInterface { public: /** + * The name of an internal variable to bind a projection post image to, which is used by the + * '_rootReplacementExpression' to replace the content of the transformed document. + */ + static constexpr StringData kProjectionPostImageVarName{"INTERNAL_PROJ_POST_IMAGE"_sd}; + + /** * Main entry point for a ParsedAggregationProjection. * * Throws a AssertionException if 'spec' is an invalid projection specification. @@ -185,7 +191,7 @@ public: Document applyTransformation(const Document& input) { auto output = applyProjection(input); if (_rootReplacementExpression) { - return _applyRootReplacementExpression(output); + return _applyRootReplacementExpression(input, output); } return output; } @@ -193,7 +199,8 @@ public: /** * Sets 'expr' as a root-replacement expression to this tree. A root-replacement expression, * once evaluated, will replace an entire output document. A projection post image document - * will be accessible via the $$ROOT variable is this expression needs access to it. + * will be accessible via the special variable, whose name is stored in + * 'kProjectionPostImageVarName', if this expression needs access to it. */ void setRootReplacementExpression(boost::intrusive_ptr<Expression> expr) { _rootReplacementExpression = expr; @@ -202,7 +209,10 @@ public: protected: ParsedAggregationProjection(const boost::intrusive_ptr<ExpressionContext>& expCtx, ProjectionPolicies policies) - : _expCtx(expCtx), _policies(policies) {} + : _expCtx(expCtx), + _policies(policies), + _projectionPostImageVarId{ + _expCtx->variablesParseState.defineVariable(kProjectionPostImageVarName)} {} /** * Apply the projection to 'input'. @@ -216,9 +226,10 @@ protected: boost::intrusive_ptr<Expression> _rootReplacementExpression; private: - Document _applyRootReplacementExpression(const Document& input) { + Document _applyRootReplacementExpression(const Document& input, const Document& output) { using namespace fmt::literals; + _expCtx->variables.setValue(_projectionPostImageVarId, Value{output}); auto val = _rootReplacementExpression->evaluate(input, &_expCtx->variables); uassert(51254, "Root-replacement expression must return a document, but got {}"_format( @@ -226,6 +237,11 @@ private: val.getType() == BSONType::Object); return val.getDocument(); } + + // This variable id is used to bind a projection post-image so that it can be accessed by + // root-replacement expressions which apply projection to the entire post-image document, rather + // than to a specific field. + Variables::Id _projectionPostImageVarId; }; } // namespace parsed_aggregation_projection } // namespace mongo diff --git a/src/mongo/db/pipeline/parsed_find_projection_test.cpp b/src/mongo/db/pipeline/parsed_find_projection_test.cpp index e7ae148ad77..c07f800578a 100644 --- a/src/mongo/db/pipeline/parsed_find_projection_test.cpp +++ b/src/mongo/db/pipeline/parsed_find_projection_test.cpp @@ -36,6 +36,9 @@ #include "mongo/unittest/unittest.h" namespace mongo::parsed_aggregation_projection { +constexpr auto kProjectionPostImageVarName = + parsed_aggregation_projection::ParsedAggregationProjection::kProjectionPostImageVarName; + class PositionalProjectionExecutionTest : public AggregationContextFixture { protected: auto applyPositional(const BSONObj& projSpec, @@ -47,6 +50,8 @@ protected: auto expr = make_intrusive<ExpressionInternalFindPositional>( getExpCtx(), ExpressionFieldPath::parse(getExpCtx(), "$$ROOT", getExpCtx()->variablesParseState), + ExpressionFieldPath::parse( + getExpCtx(), "$$" + kProjectionPostImageVarName, getExpCtx()->variablesParseState), path, matchExpr.get()); proj->setRootReplacementExpression(expr); @@ -64,7 +69,8 @@ protected: auto proj = ParsedAggregationProjection::create(getExpCtx(), projSpec, {}); auto expr = make_intrusive<ExpressionInternalFindSlice>( getExpCtx(), - ExpressionFieldPath::parse(getExpCtx(), "$$ROOT", getExpCtx()->variablesParseState), + ExpressionFieldPath::parse( + getExpCtx(), "$$" + kProjectionPostImageVarName, getExpCtx()->variablesParseState), path, skip, limit); @@ -87,6 +93,14 @@ TEST_F(PositionalProjectionExecutionTest, CanApplyPositionalWithInclusionProject Document{fromjson("{bar: 1, foo: [1,2,6,10]}")})); } +TEST_F(PositionalProjectionExecutionTest, AppliesProjectionToPreImage) { + ASSERT_DOCUMENT_EQ(Document{fromjson("{b: [6], c: 'abc'}")}, + applyPositional(fromjson("{b: 1, c: 1}"), + fromjson("{a: 1, b: {$gte: 5}}"), + "b", + Document{fromjson("{a: 1, b: [1,2,6,10], c: 'abc'}")})); +} + TEST_F(PositionalProjectionExecutionTest, ShouldAddInclusionFieldsAndWholeDocumentToDependencies) { auto proj = ParsedAggregationProjection::create(getExpCtx(), fromjson("{bar: 1, _id: 0}"), {}); auto match = fromjson("{bar: 1, 'foo.bar': {$gte: 5}}"); @@ -94,6 +108,8 @@ TEST_F(PositionalProjectionExecutionTest, ShouldAddInclusionFieldsAndWholeDocume auto expr = make_intrusive<ExpressionInternalFindPositional>( getExpCtx(), ExpressionFieldPath::parse(getExpCtx(), "$$ROOT", getExpCtx()->variablesParseState), + ExpressionFieldPath::parse( + getExpCtx(), "$$" + kProjectionPostImageVarName, getExpCtx()->variablesParseState), "foo.bar", matchExpr.get()); proj->setRootReplacementExpression(expr); @@ -114,6 +130,8 @@ TEST_F(PositionalProjectionExecutionTest, ShouldConsiderAllPathsAsModified) { auto expr = make_intrusive<ExpressionInternalFindPositional>( getExpCtx(), ExpressionFieldPath::parse(getExpCtx(), "$$ROOT", getExpCtx()->variablesParseState), + ExpressionFieldPath::parse( + getExpCtx(), "$$" + kProjectionPostImageVarName, getExpCtx()->variablesParseState), "foo.bar", matchExpr.get()); proj->setRootReplacementExpression(expr); @@ -136,6 +154,15 @@ TEST_F(SliceProjectionExecutionTest, CanApplySliceWithInclusionProjection) { Document{fromjson("{bar: 1, foo: [1,2,6,10]}")})); } +TEST_F(SliceProjectionExecutionTest, AppliesProjectionToPostImage) { + ASSERT_DOCUMENT_EQ(Document{fromjson("{b: [1,2], c: 'abc'}")}, + applySlice(fromjson("{b: 1, c: 1}"), + "b", + boost::none, + 2, + Document{fromjson("{a: 1, b: [1,2,6,10], c: 'abc'}")})); +} + TEST_F(SliceProjectionExecutionTest, CanApplySliceAndPositionalProjectionsTogether) { auto proj = ParsedAggregationProjection::create(getExpCtx(), fromjson("{foo: 1, bar: 1}"), {}); auto matchSpec = fromjson("{foo: {$gte: 3}}"); @@ -143,6 +170,8 @@ TEST_F(SliceProjectionExecutionTest, CanApplySliceAndPositionalProjectionsTogeth auto positionalExpr = make_intrusive<ExpressionInternalFindPositional>( getExpCtx(), ExpressionFieldPath::parse(getExpCtx(), "$$ROOT", getExpCtx()->variablesParseState), + ExpressionFieldPath::parse( + getExpCtx(), "$$" + kProjectionPostImageVarName, getExpCtx()->variablesParseState), "foo", matchExpr.get()); auto sliceExpr = @@ -166,7 +195,8 @@ TEST_F(SliceProjectionExecutionTest, auto proj = ParsedAggregationProjection::create(getExpCtx(), fromjson("{bar: 1, _id: 0}"), {}); auto expr = make_intrusive<ExpressionInternalFindSlice>( getExpCtx(), - ExpressionFieldPath::parse(getExpCtx(), "$$ROOT", getExpCtx()->variablesParseState), + ExpressionFieldPath::parse( + getExpCtx(), "$$" + kProjectionPostImageVarName, getExpCtx()->variablesParseState), "foo.bar", 1, 1); @@ -184,7 +214,8 @@ TEST_F(SliceProjectionExecutionTest, ShouldConsiderAllPathsAsModifiedWithInclusi auto proj = ParsedAggregationProjection::create(getExpCtx(), fromjson("{bar: 1}"), {}); auto expr = make_intrusive<ExpressionInternalFindSlice>( getExpCtx(), - ExpressionFieldPath::parse(getExpCtx(), "$$ROOT", getExpCtx()->variablesParseState), + ExpressionFieldPath::parse( + getExpCtx(), "$$" + kProjectionPostImageVarName, getExpCtx()->variablesParseState), "foo.bar", 1, 1); @@ -198,7 +229,8 @@ TEST_F(SliceProjectionExecutionTest, ShouldConsiderAllPathsAsModifiedWithExclusi auto proj = ParsedAggregationProjection::create(getExpCtx(), fromjson("{bar: 0}"), {}); auto expr = make_intrusive<ExpressionInternalFindSlice>( getExpCtx(), - ExpressionFieldPath::parse(getExpCtx(), "$$ROOT", getExpCtx()->variablesParseState), + ExpressionFieldPath::parse( + getExpCtx(), "$$" + kProjectionPostImageVarName, getExpCtx()->variablesParseState), "foo.bar", 1, 1); @@ -212,7 +244,8 @@ TEST_F(SliceProjectionExecutionTest, ShouldAddWholeDocumentToDependenciesWithExc auto proj = ParsedAggregationProjection::create(getExpCtx(), fromjson("{bar: 0}"), {}); auto expr = make_intrusive<ExpressionInternalFindSlice>( getExpCtx(), - ExpressionFieldPath::parse(getExpCtx(), "$$ROOT", getExpCtx()->variablesParseState), + ExpressionFieldPath::parse( + getExpCtx(), "$$" + kProjectionPostImageVarName, getExpCtx()->variablesParseState), "foo.bar", 1, 1); |