mongo/jstests/aggregation/expressions/group_accumulators_as_exprs.js

69 lines
2.7 KiB
JavaScript

// SERVER-9625 Making accumulators $sum, $min, $max, $avg, $stdDevSamp, and $stdDevPop available as
// expressions.
let coll = db.server9625;
coll.drop();
assert.commandWorked(coll.insert({}));
// Helper for testing that op returns expResult.
function testOp(op, expResult) {
let pipeline = [{$project: {_id: 0, result: op}}];
assert.eq(coll.aggregate(pipeline).toArray(), [{result: expResult}]);
}
// ExpressionFromAccumulators take either a list of arguments or a single array argument.
testOp({$avg: [1, 2, 3, 4, 5]}, 3);
testOp({$avg: [[1, 2, 3, 4, 5]]}, 3);
testOp({$min: [1, 2, 3, 4, 5]}, 1);
testOp({$min: [[1, 2, 3, 4, 5]]}, 1);
testOp({$max: [1, 2, 3, 4, 5]}, 5);
testOp({$max: [[1, 2, 3, 4, 5]]}, 5);
testOp({$sum: [1, 2, 3, 4, 5]}, 15);
testOp({$sum: [[1, 2, 3, 4, 5]]}, 15);
testOp({$stdDevPop: [1, 3]}, 1);
testOp({$stdDevPop: [[1, 3]]}, 1);
testOp({$stdDevSamp: [1, 2, 3]}, 1);
testOp({$stdDevSamp: [[1, 2, 3]]}, 1);
// Null arguments are ignored.
testOp({$avg: [1, 2, 3, 4, 5, null]}, 3);
testOp({$min: [1, 2, 3, 4, 5, null]}, 1);
testOp({$max: [1, 2, 3, 4, 5, null]}, 5);
testOp({$sum: [1, 2, 3, 4, 5, null]}, 15);
testOp({$stdDevPop: [1, 3, null]}, 1);
testOp({$stdDevSamp: [1, 2, 3, null]}, 1);
// NaN arguments are processed by all expressions.
testOp({$avg: [1, 2, 3, 4, 5, NaN]}, NaN);
testOp({$min: [1, 2, 3, 4, 5, NaN]}, NaN);
testOp({$max: [1, 2, 3, 4, 5, NaN]}, 5);
testOp({$sum: [1, 2, 3, 4, 5, NaN]}, NaN);
testOp({$stdDevPop: [1, 3, NaN]}, NaN);
testOp({$stdDevSamp: [1, 2, 3, NaN]}, NaN);
// Use at least one non-constant value in the following tests, to ensure
// isAssociative() and isCommutative() are called. If all arguments are constant, the
// optimization will evaluate them all into one, without calling isAssociative() nor
// isCommutative().
coll.drop();
assert.commandWorked(coll.insert({"a": 1, "b": 6}));
// These expressions are associative and commutative so inner expression can be combined with
// outer.
testOp({$sum: ["$a", 2, 3, {$sum: [4, 5]}]}, 15);
testOp({$min: ["$a", 2, 3, {$min: [4, 5]}]}, 1);
testOp({$max: ["$a", 2, 3, {$max: [4, 5]}]}, 5);
// These expressions are not associative and commutative so inner expression cannot be combined
// with outer.
testOp({$avg: ["$a", 3, {$avg: [4, 6]}]}, 3);
testOp({$stdDevPop: ["$a", {$stdDevPop: [1, 3]}]}, 0);
testOp({$stdDevSamp: ["$a", {$stdDevSamp: [1, 2, 3]}]}, 0);
// If isAssociative() and isCommutative() did not return false when provided a single argument,
// the single array argument provided to the inner expression would be ignored instead of
// treated as a list of arguments, and these tests would fail.
testOp({$sum: ["$a", 2, 3, {$sum: [["$a", 4, 5]]}]}, 16);
testOp({$min: ["$b", 2, 3, {$min: [["$a", 4, 5]]}]}, 1);
testOp({$max: ["$a", 2, 3, {$max: [["$b", 4, 5]]}]}, 6);