diff options
Diffstat (limited to 'jstests/aggregation/bugs/firstlast.js')
-rw-r--r-- | jstests/aggregation/bugs/firstlast.js | 225 |
1 files changed, 112 insertions, 113 deletions
diff --git a/jstests/aggregation/bugs/firstlast.js b/jstests/aggregation/bugs/firstlast.js index aa360a25b7e..8ab83fe30b7 100644 --- a/jstests/aggregation/bugs/firstlast.js +++ b/jstests/aggregation/bugs/firstlast.js @@ -2,120 +2,119 @@ * Tests the $first and $last accumulators in $group. */ (function() { - 'use strict'; - const coll = db.jstests_aggregation_firstlast; - coll.drop(); - - /** Check expected $first and $last result values. */ - function assertFirstLast(expectedFirst, expectedLast, stages, expression) { - let pipeline = [{$sort: {_id: 1}}]; - if (stages) { - pipeline = pipeline.concat(stages); - } +'use strict'; +const coll = db.jstests_aggregation_firstlast; +coll.drop(); + +/** Check expected $first and $last result values. */ +function assertFirstLast(expectedFirst, expectedLast, stages, expression) { + let pipeline = [{$sort: {_id: 1}}]; + if (stages) { + pipeline = pipeline.concat(stages); + } - expression = expression || '$b'; - pipeline.push( - {$group: {_id: '$a', first: {$first: expression}, last: {$last: expression}}}); - - const result = coll.aggregate(pipeline).toArray(); - for (let i = 0; i < result.length; ++i) { - if (result[i]._id === 1) { - // Check results for group _id 1. - assert.eq(expectedFirst, result[i].first); - assert.eq(expectedLast, result[i].last); - return; - } + expression = expression || '$b'; + pipeline.push({$group: {_id: '$a', first: {$first: expression}, last: {$last: expression}}}); + + const result = coll.aggregate(pipeline).toArray(); + for (let i = 0; i < result.length; ++i) { + if (result[i]._id === 1) { + // Check results for group _id 1. + assert.eq(expectedFirst, result[i].first); + assert.eq(expectedLast, result[i].last); + return; } - throw new Error('Expected $group _id "1" is missing'); } - - // One document. - assert.writeOK(coll.insert({a: 1, b: 1})); - assertFirstLast(1, 1); - - // Two documents. - assert.writeOK(coll.insert({a: 1, b: 2})); - assertFirstLast(1, 2); - - // Three documents. - assert.writeOK(coll.insert({a: 1, b: 3})); - assertFirstLast(1, 3); - - // Another 'a' key value does not affect outcome. - assert(coll.drop()); - assert.writeOK(coll.insert({a: 3, b: 0})); - assert.writeOK(coll.insert({a: 1, b: 1})); - assert.writeOK(coll.insert({a: 1, b: 2})); - assert.writeOK(coll.insert({a: 1, b: 3})); - assert.writeOK(coll.insert({a: 2, b: 0})); - assertFirstLast(1, 3); - - // Additional pipeline stages do not affect outcome if order is maintained. - assertFirstLast(1, 3, [{$project: {x: '$a', y: '$b'}}, {$project: {a: '$x', b: '$y'}}]); - - // Additional pipeline stages affect outcome if order is modified. - assertFirstLast(3, 1, [{$sort: {b: -1}}]); - - // Skip and limit affect the results seen. - assert(coll.drop()); - assert.writeOK(coll.insert({a: 1, b: 1})); - assert.writeOK(coll.insert({a: 1, b: 2})); - assert.writeOK(coll.insert({a: 1, b: 3})); - assertFirstLast(1, 2, [{$limit: 2}]); - assertFirstLast(2, 3, [{$skip: 1}, {$limit: 2}]); - assertFirstLast(2, 2, [{$skip: 1}, {$limit: 1}]); - - // Mixed type values. - assert.writeOK(coll.insert({a: 1, b: 'foo'})); - assertFirstLast(1, 'foo'); - - assert(coll.drop()); - assert.writeOK(coll.insert({a: 1, b: 'bar'})); - assert.writeOK(coll.insert({a: 1, b: true})); - assertFirstLast('bar', true); - - // Value null. - assert(coll.drop()); - assert.writeOK(coll.insert({a: 1, b: null})); - assert.writeOK(coll.insert({a: 1, b: 2})); - assertFirstLast(null, 2); - - assert(coll.drop()); - assert.writeOK(coll.insert({a: 1, b: 2})); - assert.writeOK(coll.insert({a: 1, b: null})); - assertFirstLast(2, null); - - assert(coll.drop()); - assert.writeOK(coll.insert({a: 1, b: null})); - assert.writeOK(coll.insert({a: 1, b: null})); - assertFirstLast(null, null); - - // Value missing. - assert(coll.drop()); - assert.writeOK(coll.insert({a: 1})); - assert.writeOK(coll.insert({a: 1, b: 2})); - assertFirstLast(undefined, 2); - - assert(coll.drop()); - assert.writeOK(coll.insert({a: 1, b: 2})); - assert.writeOK(coll.insert({a: 1})); - assertFirstLast(2, undefined); - - assert(coll.drop()); - assert.writeOK(coll.insert({a: 1})); - assert.writeOK(coll.insert({a: 1})); - assertFirstLast(undefined, undefined); - - // Dotted field. - assert(coll.drop()); - assert.writeOK(coll.insert({a: 1, b: [{c: 1}, {c: 2}]})); - assert.writeOK(coll.insert({a: 1, b: [{c: 6}, {}]})); - assertFirstLast([1, 2], [6], [], '$b.c'); - - // Computed expressions. - assert(coll.drop()); - assert.writeOK(coll.insert({a: 1, b: 1})); - assert.writeOK(coll.insert({a: 1, b: 2})); - assertFirstLast(1, 0, [], {$mod: ['$b', 2]}); - assertFirstLast(0, 1, [], {$mod: [{$add: ['$b', 1]}, 2]}); + throw new Error('Expected $group _id "1" is missing'); +} + +// One document. +assert.writeOK(coll.insert({a: 1, b: 1})); +assertFirstLast(1, 1); + +// Two documents. +assert.writeOK(coll.insert({a: 1, b: 2})); +assertFirstLast(1, 2); + +// Three documents. +assert.writeOK(coll.insert({a: 1, b: 3})); +assertFirstLast(1, 3); + +// Another 'a' key value does not affect outcome. +assert(coll.drop()); +assert.writeOK(coll.insert({a: 3, b: 0})); +assert.writeOK(coll.insert({a: 1, b: 1})); +assert.writeOK(coll.insert({a: 1, b: 2})); +assert.writeOK(coll.insert({a: 1, b: 3})); +assert.writeOK(coll.insert({a: 2, b: 0})); +assertFirstLast(1, 3); + +// Additional pipeline stages do not affect outcome if order is maintained. +assertFirstLast(1, 3, [{$project: {x: '$a', y: '$b'}}, {$project: {a: '$x', b: '$y'}}]); + +// Additional pipeline stages affect outcome if order is modified. +assertFirstLast(3, 1, [{$sort: {b: -1}}]); + +// Skip and limit affect the results seen. +assert(coll.drop()); +assert.writeOK(coll.insert({a: 1, b: 1})); +assert.writeOK(coll.insert({a: 1, b: 2})); +assert.writeOK(coll.insert({a: 1, b: 3})); +assertFirstLast(1, 2, [{$limit: 2}]); +assertFirstLast(2, 3, [{$skip: 1}, {$limit: 2}]); +assertFirstLast(2, 2, [{$skip: 1}, {$limit: 1}]); + +// Mixed type values. +assert.writeOK(coll.insert({a: 1, b: 'foo'})); +assertFirstLast(1, 'foo'); + +assert(coll.drop()); +assert.writeOK(coll.insert({a: 1, b: 'bar'})); +assert.writeOK(coll.insert({a: 1, b: true})); +assertFirstLast('bar', true); + +// Value null. +assert(coll.drop()); +assert.writeOK(coll.insert({a: 1, b: null})); +assert.writeOK(coll.insert({a: 1, b: 2})); +assertFirstLast(null, 2); + +assert(coll.drop()); +assert.writeOK(coll.insert({a: 1, b: 2})); +assert.writeOK(coll.insert({a: 1, b: null})); +assertFirstLast(2, null); + +assert(coll.drop()); +assert.writeOK(coll.insert({a: 1, b: null})); +assert.writeOK(coll.insert({a: 1, b: null})); +assertFirstLast(null, null); + +// Value missing. +assert(coll.drop()); +assert.writeOK(coll.insert({a: 1})); +assert.writeOK(coll.insert({a: 1, b: 2})); +assertFirstLast(undefined, 2); + +assert(coll.drop()); +assert.writeOK(coll.insert({a: 1, b: 2})); +assert.writeOK(coll.insert({a: 1})); +assertFirstLast(2, undefined); + +assert(coll.drop()); +assert.writeOK(coll.insert({a: 1})); +assert.writeOK(coll.insert({a: 1})); +assertFirstLast(undefined, undefined); + +// Dotted field. +assert(coll.drop()); +assert.writeOK(coll.insert({a: 1, b: [{c: 1}, {c: 2}]})); +assert.writeOK(coll.insert({a: 1, b: [{c: 6}, {}]})); +assertFirstLast([1, 2], [6], [], '$b.c'); + +// Computed expressions. +assert(coll.drop()); +assert.writeOK(coll.insert({a: 1, b: 1})); +assert.writeOK(coll.insert({a: 1, b: 2})); +assertFirstLast(1, 0, [], {$mod: ['$b', 2]}); +assertFirstLast(0, 1, [], {$mod: [{$add: ['$b', 1]}, 2]}); }()); |