pipeline: [] | [stage, ...] stage: geoNear | group | limit | match | out | project | redact | skip | sort | unwind geoNear : {$geoNear: {GEO_NEAR_OPTIONS}} group : {$group : { _id: expression, (out_name: {accumulator: expression})* }} // accumulators are optional accumulator: $addToSet | $avg | $first | $last | $max | $min | $push | $sum limit : {$limit: natural_number} match : {$match : MATCH_EXPRESSION} // MATCH_EXPRESSION uses find syntax out : {$out: collection_name} project : {$project: inclusion_expression_top_level} inclusion_expression_top_level : { (_id: (0 | false), )? , field_name : (1 | true | expression | inclusion_expression), ... } // field_name CAN have dots inclusion_expression : { field_name : (1 | true | expression | inclusion_expression), ... } // field_name CANNOT have dots redact : {$redact: expression} // expression must result in either KEEP, DESCEND, or PRUNE skip : {$skip: natural_number} sort : {field_name: (1 | -1 | {$meta: "textScore"}), ...} // field_name ignored for $meta sorts unwind : {$unwind: field_path} expression : variable | field_path | expr_simple | expr_obj | expr_special | expr_implicit_literal variable : "$$foo" + (".asdf")* field_path : "$foo" + (".asdf")* expr_simple : expr_simple_variadic | expr_simple_1 | expr_simple_2 | expr_simple_3 expr_simple_variadic : {expr_name_var: ([] | [expression, ...] | expression)} // arrays are assumed to be arg list rather than implicit literals expr_simple_1 : {expr_name_1: ([expression] | expression)} // arrays are assumed to be arg list rather than implicit literals expr_simple_2 : {expr_name_2: [expression, expression]} expr_simple_3 : {expr_name_3: [expression, expression, expression]} // Search for ExpressionFixedArity and ExpressionVariadic expr_name_var: $add | $and | $concat | $multiply | $or | $setEquals | $setIntersection | $setUnion expr_name_1: $allElementsTrue | $allElementsFalse | $dayOfWeek | $dayOfMonth | $dayOfYear | $hour | $millisecond | $minute | $month | $not | $second | $size | $toLower | $toUpper | $week | $year expr_name_2: $compare | $divide | $ifNull | $mod | $setDifference | $isSubset | $strcasecomp | $subtract expr_name_3: $cond | $substr expr_obj: {} | {field_name: expression, ...} // expression can't be a literal number or bool expr_special : expr_literal | expr_let | expr_map | expr_meta | expr_cond_named expr_literal : {$literal : anything} // anything is unparsed and treated as a constant. $const is also supported, but undocumented expr_let : {$let: {vars: {name: expression, ...}, in: expression}} expr_map : {$map: {input: expression, as: var_name, in: expression}} expr_meta : {$meta: "textScore"} expr_cond_named : {$cond: {if: expression, then: expression, else: expression}} // $cond also supported expr_simple_3 syntax with positional arguments expr_implicit_literal : anything that isn't an object and doesn't match one of the other expr types is treated as a literal. Use of implicit literal numbers and bools is disallowed inside expr_obj