diff options
author | Jennifer Peshansky <jennifer.peshansky@mongodb.com> | 2022-11-03 16:13:20 +0000 |
---|---|---|
committer | Jennifer Peshansky <jennifer.peshansky@mongodb.com> | 2022-11-03 16:13:20 +0000 |
commit | e74d2910bbe76790ad131d53fee277829cd95982 (patch) | |
tree | cabe148764529c9623652374fbc36323a550cd44 /src/mongo/db/pipeline/abt/match_expression_visitor.cpp | |
parent | 280145e9940729480bb8a35453d4056afac87641 (diff) | |
parent | ba467f46cc1bc49965e1d72b541eff0cf1d7b22e (diff) | |
download | mongo-e74d2910bbe76790ad131d53fee277829cd95982.tar.gz |
Merge branch 'master' into jenniferpeshansky/SERVER-70854jenniferpeshansky/SERVER-70854
Diffstat (limited to 'src/mongo/db/pipeline/abt/match_expression_visitor.cpp')
-rw-r--r-- | src/mongo/db/pipeline/abt/match_expression_visitor.cpp | 80 |
1 files changed, 34 insertions, 46 deletions
diff --git a/src/mongo/db/pipeline/abt/match_expression_visitor.cpp b/src/mongo/db/pipeline/abt/match_expression_visitor.cpp index e422dc24d63..70be6fd3651 100644 --- a/src/mongo/db/pipeline/abt/match_expression_visitor.cpp +++ b/src/mongo/db/pipeline/abt/match_expression_visitor.cpp @@ -73,11 +73,11 @@ public: ABTMatchExpressionPreVisitor(ExpressionAlgebrizerContext& ctx) : _ctx(ctx) {} void visit(const ElemMatchObjectMatchExpression* expr) override { - _ctx.enterElemMatch(); + _ctx.enterElemMatch(expr->matchType()); } void visit(const ElemMatchValueMatchExpression* expr) override { - _ctx.enterElemMatch(); + _ctx.enterElemMatch(expr->matchType()); } private: @@ -135,8 +135,8 @@ public: assertSupportedPathExpression(expr); ABT result = make<PathDefault>(Constant::boolean(false)); - if (!expr->path().empty()) { - result = generateFieldPath(FieldPath(expr->path().toString()), std::move(result)); + if (shouldGeneratePath(expr)) { + result = translateFieldRef(*(expr->fieldRef()), std::move(result)); } _ctx.push(std::move(result)); } @@ -227,9 +227,9 @@ public: maybeComposePath<PathComposeA>(result, make<PathDefault>(Constant::boolean(true))); } - // The path can be empty if we are within an $elemMatch. In this case elemMatch would - // insert a traverse. - if (!expr->path().empty()) { + // Do not insert a traverse if within an $elemMatch; traversal will be handled by the + // $elemMatch expression itself. + if (shouldGeneratePath(expr)) { // When the path we are comparing is a path to an array, the comparison is // considered true if it evaluates to true for the array itself or for any of the // array’s elements. 'result' evaluates comparison on the array elements, and @@ -249,7 +249,7 @@ public: make<Constant>(tagArraysOnly, valArraysOnly))); arrOnlyGuard.reset(); } - result = generateFieldPath(FieldPath(expr->path().toString()), std::move(result)); + result = translateFieldRef(*(expr->fieldRef()), std::move(result)); } _ctx.push(std::move(result)); } @@ -426,14 +426,8 @@ public: make<FunctionCall>("getArraySize", makeSeq(make<Variable>(lambdaProjName))), Constant::int64(expr->getData())))); - if (!expr->path().empty()) { - // No traverse. - result = translateFieldPath( - FieldPath(expr->path().toString()), - std::move(result), - [](const std::string& fieldName, const bool /*isLastElement*/, ABT input) { - return make<PathGet>(fieldName, std::move(input)); - }); + if (shouldGeneratePath(expr)) { + result = translateFieldRef(*(expr->fieldRef()), std::move(result)); } _ctx.push(std::move(result)); } @@ -460,9 +454,7 @@ public: makeSeq(make<Variable>(lambdaProjName), Constant::int32(expr->typeSet().getBSONTypeMask()))))); - // The path can be empty if we are within an $elemMatch. In this case elemMatch would insert - // a traverse. - if (!expr->path().empty()) { + if (shouldGeneratePath(expr)) { result = make<PathTraverse>(std::move(result), PathTraverse::kSingleLevel); if (expr->typeSet().hasType(BSONType::Array)) { // If we are testing against array type, insert a comparison against the @@ -470,7 +462,7 @@ public: result = make<PathComposeA>(make<PathArr>(), std::move(result)); } - result = generateFieldPath(FieldPath(expr->path().toString()), std::move(result)); + result = translateFieldRef(*(expr->fieldRef()), std::move(result)); } _ctx.push(std::move(result)); } @@ -517,33 +509,13 @@ private: // Make sure we consider only arrays fields on the path. maybeComposePath(result, make<PathArr>()); - if (!expr->path().empty()) { - result = translateFieldPath( - FieldPath{expr->path().toString()}, - std::move(result), - [&](const std::string& fieldName, const bool isLastElement, ABT input) { - if (!isLastElement) { - input = make<PathTraverse>(std::move(input), PathTraverse::kSingleLevel); - } - return make<PathGet>(fieldName, std::move(input)); - }); + if (shouldGeneratePath(expr)) { + result = translateFieldRef(*(expr->fieldRef()), std::move(result)); } _ctx.push(std::move(result)); } - ABT generateFieldPath(const FieldPath& fieldPath, ABT initial) { - return translateFieldPath( - fieldPath, - std::move(initial), - [&](const std::string& fieldName, const bool isLastElement, ABT input) { - if (!isLastElement) { - input = make<PathTraverse>(std::move(input), PathTraverse::kSingleLevel); - } - return make<PathGet>(fieldName, std::move(input)); - }); - } - void assertSupportedPathExpression(const PathMatchExpression* expr) { uassert(ErrorCodes::InternalErrorNotSupported, "Expression contains a numeric path component", @@ -610,9 +582,7 @@ private: break; } - // The path can be empty if we are within an $elemMatch. In this case elemMatch would - // insert a traverse. - if (!expr->path().empty()) { + if (shouldGeneratePath(expr)) { if (tag == sbe::value::TypeTags::Array || tag == sbe::value::TypeTags::MinKey || tag == sbe::value::TypeTags::MaxKey) { // The behavior of PathTraverse when it encounters an array is to apply its subpath @@ -628,8 +598,9 @@ private: result = make<PathTraverse>(std::move(result), PathTraverse::kSingleLevel); } - result = generateFieldPath(FieldPath(expr->path().toString()), std::move(result)); + result = translateFieldRef(*(expr->fieldRef()), std::move(result)); } + _ctx.push(std::move(result)); } @@ -659,6 +630,23 @@ private: str::stream() << "Match expression is not supported: " << expr->matchType()); } + /** + * Returns whether the currently visiting expression should consider the path it's operating on + * and build the appropriate ABT. This can return false for expressions within an $elemMatch + * that operate against each value in an array (aka "elemMatch value"). + */ + bool shouldGeneratePath(const PathMatchExpression* expr) const { + // The only case where any expression, including $elemMatch, should ignore it's path is if + // it's directly under a value $elemMatch. The 'elemMatchStack' includes 'expr' if it's an + // $elemMatch, so we need to look back an extra element. + if (expr->matchType() == MatchExpression::MatchType::ELEM_MATCH_OBJECT || + expr->matchType() == MatchExpression::MatchType::ELEM_MATCH_VALUE) { + return _ctx.shouldGeneratePathForElemMatch(); + } + + return _ctx.shouldGeneratePath(); + } + // If we are parsing a partial index filter, we don't allow agg expressions. const bool _allowAggExpressions; |