summaryrefslogtreecommitdiff
path: root/jstests/aggregation/bugs/server9625.js
blob: 2cf1353f53d6f56739efd5d4d73de0de46dc74c5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// SERVER-9625 Making accumulators $sum, $min, $max, $avg, $stdDevSamp, and $stdDevPop available as
// expressions.

// For assertErrorCode.
load('jstests/aggregation/extras/utils.js');

(function() {
'use strict';
var coll = db.server9625;
coll.drop();
assert.commandWorked(coll.insert({}));

// Helper for testing that op returns expResult.
function testOp(op, expResult) {
    var 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);
}());