Uploaded image for project: 'Core Server'
  1. Core Server
  2. SERVER-74298

Implement renaming by path component for PathMatchExpression

    • Type: Icon: Improvement Improvement
    • Resolution: Unresolved
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: None
    • Component/s: None
    • Labels:
      None
    • Query Optimization

      While working on SERVER-73914, we realized that the current renaming algorithm does not support renaming by path component but we'd better to since it would support more splittable and renameable match expressions and hence achieve the better optimization. For example,

      assuming that we have a pipeline like

      [
          {
              $project: {
                  x: {
                      $map: {input: '$a', as: 'i', in : {y: '$$i.b'}}
                  }
              }
          },
          {$match: {x: {y: 1}}}
      ]
      

      the above $match should be able to be swapped with $project because $project is a simple rename.

      But as of today, there are two related issues to support the above match expression.

      1) semantic_analysis::extractModifiedDependencies() reports the path 'x' as a modified dependency and call splitMatchExpressionBy(expr, fields = {"x"}, renames = {"x.y" -> "a.b"}) and hence the expr is not splittable and cannot be swapped with $project.
      2) PathMatchExpression::applyRename() cannot rename sub-fields of prefix of renamed paths.

      We have the same issue for $elemMatch.

      Search for SERVER-74298 for more details on what to do.

      Also this note might be helpful.

      And also this analysis too:
      Right now, the match_expression::addDependencies() that uses DependencyVisitor does not report the sub-object field paths as dependencies. https://github.com/10gen/mongo/blob/38e430eb3e2ef271f958c165d5d50c38c956363e/src/mongo/db/matcher/match_expression_dependencies.cpp#L119

      For example, {d: {$elemMatch: {e: 1, f: 1}} is transformed to the following tree:

                                  $elemMatch
                                  /         \
                                 d         $and
                                          /     \
                                        $eq     $eq
                                       /   \   /   \
                                      e     1 f     1
      

      And the DependencyVisitor reports only “d” as the dependency, neither “d.e” nor “d.f”. So, if “d.e” and “d.f” happen to be renamed paths from “a.b” and “a.c” by the previous $project stage, for example,

      {{{$project: {d: {$map: {input: "$a", as: "i", in: {e: "$$i.b", f: "$$i.c"}}}}}
      {{{$match: {d: {$elemMatch: {e: 1, f: 1}}}}
      

      The $project reports renamed paths [\{d.e, a.b}, \{d.f, a.c}] but the DependencyVisitor only reports “d” as the dependency. So, we should not be able to rename “d.e” and “d.f” because “d” itself is neither a renamed nor preserved path and hence considered as a modified path by extractModifiedDependencies().

      I noticed that “d.e” and “d.f” are also not renameable in the following example:

      {$project: {d: {$map: {input: "$a", as: "i", in: {e: "$$i.b", f: "$$i.c"}}}}}
      {$match: {d: {e: 1, f: 1}}}
      

      The {d: {e: 1, f: 1}} is transformed to the following tree:

                                      $eq
                                     /   \
                                    d  {e: 1, f: 1}
      

      Interestingly enough, {e: 1, f: 1} is not transformed to an $and expression at all. So, even though we have $elemMatch object expression renameable by sub path component, we would still have an issue with $eq match against an object.

            Assignee:
            backlog-query-optimization [DO NOT USE] Backlog - Query Optimization
            Reporter:
            yoonsoo.kim@mongodb.com Yoon Soo Kim
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated: