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

$and and $or expressions may not short circuit non constants and optimize to a constant if the original expression has only one constant

    • Type: Icon: Improvement Improvement
    • Resolution: Done
    • Priority: Icon: Major - P3 Major - P3
    • 2.5.3
    • Affects Version/s: None
    • Component/s: Aggregation Framework
    • None

      Observed behavior: A $and/$or expression with a single constant is not optimized as well as a similar expression with two constants.
      Expected behavior: An expression with one constant should be optimized the same way as a similar expression with two constants.

      ExpressionAnd::optimize() and ExpressionOr::optimize() expect that any constant will appear in the last operand, but ExpressionNary::optimize() does not guarantee placement of a constant in the last operand if there was only one constant to begin with.

              /*
                If there's no more than one constant, then we can't do any
                constant folding, so don't bother going any further.
               */
              if (constCount <= 1)
                  return intrusive_ptr<Expression>(this);
      

      Test:

      c = db.c;
      c.drop();
      
      c.save( { x:true } );
      
      // This expression is left as is.
      printjson( c.runCommand( 'aggregate', { pipeline:[ { $project:{ a:{ $and:[ 0, '$x' ] } }\
       } ], explain:true } ) );
      // This expression is optimized to 'false', eliminating the need to read field 'x', due to the existence of two constant operands.
      printjson( c.runCommand( 'aggregate', { pipeline:[ { $project:{ a:{ $and:[ 0, 1, '$x' ] \
      } } } ], explain:true } ) );
      
      // This expression is left as is.
      printjson( c.runCommand( 'aggregate', { pipeline:[ { $project:{ a:{ $or:[ 1, '$x' ] } } \
      } ], explain:true } ) );
      // This expression is optimized to 'true', eliminating the need to read field 'x', due to the existence of two constant operands.
      printjson( c.runCommand( 'aggregate', { pipeline:[ { $project:{ a:{ $or:[ 1, 0, '$x' ] }\
       } } ], explain:true } ) );
      

            Assignee:
            david.storch@mongodb.com David Storch
            Reporter:
            aaron Aaron Staple
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: