diff options
Diffstat (limited to 'jstests/aggregation/bugs')
| -rw-r--r-- | jstests/aggregation/bugs/empty_field_names.js | 19 | ||||
| -rw-r--r-- | jstests/aggregation/bugs/groupMissing.js | 62 | ||||
| -rw-r--r-- | jstests/aggregation/bugs/hash_lookup_spill_large_and_small_documents_correctly.js | 74 | ||||
| -rw-r--r-- | jstests/aggregation/bugs/server18427.js | 159 | ||||
| -rw-r--r-- | jstests/aggregation/bugs/server6570.js | 23 | ||||
| -rw-r--r-- | jstests/aggregation/bugs/server72651.js | 12 | ||||
| -rw-r--r-- | jstests/aggregation/bugs/timeseries_should_not_push_match_before_project.js | 30 | ||||
| -rw-r--r-- | jstests/aggregation/bugs/window_inside_facet.js | 77 |
8 files changed, 193 insertions, 263 deletions
diff --git a/jstests/aggregation/bugs/empty_field_names.js b/jstests/aggregation/bugs/empty_field_names.js deleted file mode 100644 index 04429027e51..00000000000 --- a/jstests/aggregation/bugs/empty_field_names.js +++ /dev/null @@ -1,19 +0,0 @@ -// Testing documents that contain empty field names. This was written as part of -// SERVER-86619. -db.emptyFields.drop(); -db.createCollection('emptyFields'); - -const kNumDocs = 50; - -for (let i = 0; i < 50; ++i) { - db.emptyFields.insert({"": 123, "b": 456, sortField: i}); -} - -assert.eq(db.emptyFields - .aggregate([ - {$sort: {sortField: 1}}, - {$addFields: {"m": {$meta: "sortKey"}}}, - {$match: {"b": 456}} - ]) - .itcount(), - kNumDocs); diff --git a/jstests/aggregation/bugs/groupMissing.js b/jstests/aggregation/bugs/groupMissing.js index ba6b0f58fff..f13477a90b6 100644 --- a/jstests/aggregation/bugs/groupMissing.js +++ b/jstests/aggregation/bugs/groupMissing.js @@ -7,23 +7,23 @@ // @tags: [ // do_not_wrap_aggregations_in_facets, // ] -load('jstests/aggregation/extras/utils.js'); // For assertArrayEq. +load('jstests/aggregation/extras/utils.js'); // For resultsEq. (function() { "use strict"; -const coll = db.getCollection(jsTestName()); +var coll = db.groupMissing; coll.drop(); -assert.commandWorked(coll.insert({a: null})); -assert.commandWorked(coll.insert({})); +coll.insert({a: null}); +coll.insert({}); -let res = coll.aggregate({$group: {_id: "$a"}}); -let arr = res.toArray(); +var res = coll.aggregate({$group: {_id: "$a"}}); +var arr = res.toArray(); assert.eq(arr.length, 1); assert.eq(arr[0]._id, null); -assert.commandWorked(coll.createIndex({a: 1})); +coll.createIndex({a: 1}); res = coll.aggregate({$sort: {a: 1}}, {$group: {_id: "$a"}}); arr = res.toArray(); assert.eq(arr.length, 1); @@ -31,49 +31,41 @@ assert.eq(arr[0]._id, null); coll.drop(); -assert.commandWorked(coll.insert({a: null})); -assert.commandWorked(coll.insert({})); +coll.insert({a: null}); +coll.insert({}); // Bug, see SERVER-21992. res = coll.aggregate({$group: {_id: {a: "$a"}}}); -assertArrayEq({actual: res.toArray(), expected: [{_id: {a: null}}]}); +assert(resultsEq(res.toArray(), [{_id: {a: null}}])); // Bug, see SERVER-21992. -assert.commandWorked(coll.createIndex({a: 1})); +coll.createIndex({a: 1}); res = coll.aggregate({$group: {_id: {a: "$a"}}}); -assertArrayEq({actual: res.toArray(), expected: [{_id: {a: null}}]}); +assert(resultsEq(res.toArray(), [{_id: {a: null}}])); // Correct behavior after SERVER-21992 is fixed. if (0) { res = coll.aggregate({$group: {_id: {a: "$a"}}}); - assertArrayEq({actual: res.toArray(), expected: [{_id: {a: null}}, {_id: {}}]}); + assert(resultsEq(res.toArray(), [{_id: {a: null}}, {_id: {}}])); } coll.drop(); -assert.commandWorked(coll.insert({a: null, b: 1})); -assert.commandWorked(coll.insert({b: 1})); -assert.commandWorked(coll.insert({a: null, b: 1})); +coll.insert({a: null, b: 1}); +coll.insert({b: 1}); +coll.insert({a: null, b: 1}); res = coll.aggregate({$group: {_id: {a: "$a", b: "$b"}}}); -assertArrayEq({actual: res.toArray(), expected: [{_id: {b: 1}}, {_id: {a: null, b: 1}}]}); +assert(resultsEq(res.toArray(), [{_id: {b: 1}}, {_id: {a: null, b: 1}}])); -assert.commandWorked(coll.createIndex({a: 1, b: 1})); -res = coll.aggregate([{$group: {_id: {a: "$a", b: "$b"}}}, {$sort: {"_id.a": 1, "_id.b": 1}}]); -// Before fixing SERVER-23229 we were getting [{_id: {a: null, b: 1}}] -assertArrayEq({actual: res.toArray(), expected: [{_id: {b: 1}}, {_id: {a: null, b: 1}}]}); +// Bug, see SERVER-23229. +coll.createIndex({a: 1, b: 1}); +res = coll.aggregate({$sort: {a: 1, b: 1}}, {$group: {_id: {a: "$a", b: "$b"}}}); +assert(resultsEq(res.toArray(), [{_id: {a: null, b: 1}}])); -// Try another variation of the query that is taken more directly from the bug report SERVER-23229. -coll.drop(); -assert.commandWorked(coll.insert({a: 1, b: null})); -assert.commandWorked(coll.insert({a: null, b: 1})); -assert.commandWorked(coll.insert({b: 1})); -assert.commandWorked(coll.insert({a: 1})); - -let preSortResult = - coll.aggregate({$sort: {a: 1, b: 1}}, {$group: {_id: {a: "$a", b: "$b"}}}).toArray(); -assert.commandWorked(coll.createIndex({a: 1, b: 1})); -assertArrayEq({ - actual: preSortResult, - expected: coll.aggregate({$group: {_id: {a: "$a", b: "$b"}}}).toArray() -}); +// Correct behavior after SERVER-23229 is fixed. +if (0) { + coll.createIndex({a: 1, b: 1}); + res = coll.aggregate({$sort: {a: 1, b: 1}}, {$group: {_id: {a: "$a", b: "$b"}}}); + assert(resultsEq(res.toArray(), [{_id: {b: 1}}, {_id: {a: null, b: 1}}])); +} }()); diff --git a/jstests/aggregation/bugs/hash_lookup_spill_large_and_small_documents_correctly.js b/jstests/aggregation/bugs/hash_lookup_spill_large_and_small_documents_correctly.js deleted file mode 100644 index de8f79bbea7..00000000000 --- a/jstests/aggregation/bugs/hash_lookup_spill_large_and_small_documents_correctly.js +++ /dev/null @@ -1,74 +0,0 @@ -// Regression test to check that different document sizes work correctly with $lookup. -// @tags: [ -// requires_fcv_71, -// ] -(function() { -'use strict'; - -load('jstests/libs/fixture_helpers.js'); // For 'FixtureHelpers' - -const localColl = db.lookup_spill_local; -const foreignColl = db.lookup_spill_foreign; -localColl.drop(); -foreignColl.drop(); - -const memoryLimit = 128; // Spill at 128 bytes - -function setHashLookupMemoryLimit(memoryLimit) { - const commandResArr = FixtureHelpers.runCommandOnEachPrimary({ - db: db.getSiblingDB("admin"), - cmdObj: { - setParameter: 1, - internalQuerySlotBasedExecutionHashLookupApproxMemoryUseInBytesBeforeSpill: memoryLimit, - } - }); - assert.gt(commandResArr.length, 0, "Setting memory limit on primaries failed"); - assert.commandWorked(commandResArr[0]); -} - -function runHashLookupSpill() { - const smallStr = "small"; - const bigStr = Array(memoryLimit).toString(); - const localDoc = {_id: 1, a: 2}; - const foreignDocs = [ - {_id: 0, b: 1, padding: smallStr}, - {_id: 1, b: 2, padding: bigStr}, - {_id: 2, b: 1, padding: smallStr}, - {_id: 3, b: 2, padding: bigStr}, - {_id: 4, b: 1, padding: smallStr}, - {_id: 5, b: 2, padding: bigStr}, - {_id: 6, b: 1, padding: smallStr}, - {_id: 7, b: 2, padding: bigStr}, - {_id: 8, b: 1, padding: smallStr}, - ]; - - assert.commandWorked(localColl.insert(localDoc)); - assert.commandWorked(foreignColl.insertMany(foreignDocs)); - const pipeline = [ - {$lookup: {from: foreignColl.getName(), localField: "a", foreignField: "b", as: "matched"}}, - {$sort: {_id: 1}} - ]; - - const result = localColl.aggregate(pipeline).toArray(); - assert.eq(result.length, 1, result); - assert.eq(result[0].matched.length, 4, result); - for (let matched of result[0].matched) { - assert.eq(matched.padding, bigStr); - } -} - -const oldMemoryLimit = - assert - .commandWorked(db.adminCommand({ - getParameter: 1, - internalQuerySlotBasedExecutionHashLookupApproxMemoryUseInBytesBeforeSpill: 1 - })) - .internalQuerySlotBasedExecutionHashLookupApproxMemoryUseInBytesBeforeSpill; - -try { - setHashLookupMemoryLimit(memoryLimit); - runHashLookupSpill(); -} finally { - setHashLookupMemoryLimit(oldMemoryLimit); -} -})(); diff --git a/jstests/aggregation/bugs/server18427.js b/jstests/aggregation/bugs/server18427.js new file mode 100644 index 00000000000..a633632ab3d --- /dev/null +++ b/jstests/aggregation/bugs/server18427.js @@ -0,0 +1,159 @@ +// SERVER-18427: Add $log, $log10, $ln, $pow, and $exp aggregation expressions. + +// For assertErrorCode. +load('jstests/aggregation/extras/utils.js'); +load('jstests/libs/sbe_assert_error_override.js'); // Override error-code-checking APIs. + +(function() { +'use strict'; +var coll = db.log_exponential_expressions; +coll.drop(); +assert.commandWorked(coll.insert({_id: 0, a: 8, b: 2})); + +var decimalE = NumberDecimal("2.718281828459045235360287471352662"); +var decimal1overE = NumberDecimal("0.3678794411714423215955237701614609"); + +// 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}]); +} + +// $log, $log10, $ln. + +// Valid input: numeric/null/NaN, base positive and not equal to 1, arg positive. +// - NumberDouble +testOp({$log: [10, 10]}, 1); +testOp({$log10: [10]}, 1); +testOp({$ln: [Math.E]}, 1); +// - NumberDecimal +testOp({$log: [NumberDecimal("10"), NumberDecimal("10")]}, NumberDecimal("1")); +testOp({$log10: [NumberDecimal("10")]}, NumberDecimal("1")); +// The below answer is actually correct: the input is an approximation of E +testOp({$ln: [decimalE]}, NumberDecimal("0.9999999999999999999999999999999998")); +// All types converted to doubles. +testOp({$log: [NumberLong("10"), NumberLong("10")]}, 1); +testOp({$log10: [NumberLong("10")]}, 1); +testOp({$ln: [NumberLong("1")]}, 0); +// LLONG_MAX is converted to a double. +testOp({$log: [NumberLong("9223372036854775807"), 10]}, 18.964889726830812); +// Null inputs result in null. +testOp({$log: [null, 10]}, null); +testOp({$log: [10, null]}, null); +testOp({$log: [null, NumberDecimal(10)]}, null); +testOp({$log: [NumberDecimal(10), null]}, null); +testOp({$log10: [null]}, null); +testOp({$ln: [null]}, null); +// NaN inputs result in NaN. +testOp({$log: [NaN, 10]}, NaN); +testOp({$log: [10, NaN]}, NaN); +testOp({$log: [NaN, NumberDecimal(10)]}, NaN); +testOp({$log: [NumberDecimal(10), NaN]}, NaN); +testOp({$log10: [NaN]}, NaN); +testOp({$ln: [NaN]}, NaN); + +// Test that $log still works when the inputs are field path expressions, meaning that the +// expression is not eligible for constant folding. +testOp({$log: ["$a", "$b"]}, 3); + +// Invalid input: non-numeric/non-null, bases not positive or equal to 1, args not positive. + +// Args/bases must be numeric or null. +assertErrorCode(coll, [{$project: {log: {$log: ["string", 5]}}}], 28756); +assertErrorCode(coll, [{$project: {log: {$log: [5, "string"]}}}], 28757); +assertErrorCode(coll, [{$project: {log10: {$log10: ["string"]}}}], 28765); +assertErrorCode(coll, [{$project: {ln: {$ln: ["string"]}}}], 28765); +// Args/bases cannot equal 0. +assertErrorCode(coll, [{$project: {log: {$log: [0, 5]}}}], 28758); +assertErrorCode(coll, [{$project: {log: {$log: [5, 0]}}}], 28759); +assertErrorCode(coll, [{$project: {log10: {$log10: [0]}}}], 28761); +assertErrorCode(coll, [{$project: {ln: {$ln: [0]}}}], 28766); +assertErrorCode(coll, [{$project: {log: {$log: [NumberDecimal(0), NumberDecimal(5)]}}}], 28758); +assertErrorCode(coll, [{$project: {log: {$log: [NumberDecimal(5), NumberDecimal(0)]}}}], 28759); +assertErrorCode(coll, [{$project: {log10: {$log10: [NumberDecimal(0)]}}}], 28761); +assertErrorCode(coll, [{$project: {ln: {$ln: [NumberDecimal(0)]}}}], 28766); +// Args/bases cannot be negative. +assertErrorCode(coll, [{$project: {log: {$log: [-1, 5]}}}], 28758); +assertErrorCode(coll, [{$project: {log: {$log: [5, -1]}}}], 28759); +assertErrorCode(coll, [{$project: {log10: {$log10: [-1]}}}], 28761); +assertErrorCode(coll, [{$project: {ln: {$ln: [-1]}}}], 28766); +assertErrorCode(coll, [{$project: {log: {$log: [NumberDecimal(-1), NumberDecimal(5)]}}}], 28758); +assertErrorCode(coll, [{$project: {log: {$log: [NumberDecimal(5), NumberDecimal(-1)]}}}], 28759); +assertErrorCode(coll, [{$project: {log10: {$log10: [NumberDecimal(-1)]}}}], 28761); +assertErrorCode(coll, [{$project: {ln: {$ln: [NumberDecimal(-1)]}}}], 28766); +// Base can't equal 1. +assertErrorCode(coll, [{$project: {log: {$log: [5, 1]}}}], 28759); +assertErrorCode(coll, [{$project: {log: {$log: [NumberDecimal(5), NumberDecimal(1)]}}}], 28759); + +// $pow, $exp. + +// Valid input - numeric/null/NaN. + +// $pow -- if either input is a double return a double. +testOp({$pow: [10, 2]}, 100); +testOp({$pow: [1 / 2, -1]}, 2); +testOp({$pow: [-2, 2]}, 4); +testOp({$pow: [NumberInt("2"), 2]}, 4); +testOp({$pow: [-2, NumberInt("2")]}, 4); +// $pow -- if either input is a NumberDecimal, return a NumberDecimal +testOp({$pow: [NumberDecimal("10.0"), -2]}, NumberDecimal("0.01000000000000000000000000000000000")); +testOp({$pow: [0.5, NumberDecimal("-1")]}, NumberDecimal("2.000000000000000000000000000000000")); +testOp({$pow: [-2, NumberDecimal("2")]}, NumberDecimal("4.000000000000000000000000000000000")); +testOp({$pow: [NumberInt("2"), NumberDecimal("2")]}, + NumberDecimal("4.000000000000000000000000000000000")); +testOp({$pow: [NumberDecimal("-2.0"), NumberInt("2")]}, + NumberDecimal("4.000000000000000000000000000000000")); +testOp({$pow: [NumberDecimal("10.0"), 2]}, NumberDecimal("100.0000000000000000000000000000000")); + +// If exponent is negative and base not -1, 0, or 1, return a double. +testOp({$pow: [NumberLong("2"), NumberLong("-1")]}, 1 / 2); +testOp({$pow: [NumberInt("4"), NumberInt("-1")]}, 1 / 4); +testOp({$pow: [NumberInt("4"), NumberLong("-1")]}, 1 / 4); +testOp({$pow: [NumberInt("1"), NumberLong("-2")]}, NumberLong("1")); +testOp({$pow: [NumberInt("-1"), NumberLong("-2")]}, NumberLong("1")); +testOp({$pow: [NumberLong("-1"), NumberLong("-3")]}, NumberLong("-1")); +// If result would overflow a long, return a double. +testOp({$pow: [NumberInt("2"), NumberLong("63")]}, 9223372036854776000); +// Exact decimal result +testOp({$pow: [NumberInt("5"), NumberDecimal("-112")]}, + NumberDecimal("5192296858534827628530496329220096E-112")); + +// Result would be incorrect if double were returned. +testOp({$pow: [NumberInt("3"), NumberInt("35")]}, NumberLong("50031545098999707")); + +// Else if either input is a long, return a long. +testOp({$pow: [NumberInt("-2"), NumberLong("63")]}, NumberLong("-9223372036854775808")); +testOp({$pow: [NumberInt("4"), NumberLong("2")]}, NumberLong("16")); +testOp({$pow: [NumberLong("4"), NumberInt("2")]}, NumberLong("16")); +testOp({$pow: [NumberLong("4"), NumberLong("2")]}, NumberLong("16")); + +// Else return an int if it fits. +testOp({$pow: [NumberInt("4"), NumberInt("2")]}, 16); + +// $exp always returns doubles for non-zero non-decimal inputs, since e is a double. +testOp({$exp: [NumberInt("-1")]}, 1 / Math.E); +testOp({$exp: [NumberLong("1")]}, Math.E); +// $exp returns decimal results for decimal inputs +testOp({$exp: [NumberDecimal("-1")]}, decimal1overE); +testOp({$exp: [NumberDecimal("1")]}, decimalE); +// Null input results in null. +testOp({$pow: [null, 2]}, null); +testOp({$pow: [1 / 2, null]}, null); +testOp({$pow: [null, NumberDecimal(2)]}, null); +testOp({$pow: [NumberDecimal("0.5"), null]}, null); +testOp({$exp: [null]}, null); +// NaN input results in NaN. +testOp({$pow: [NaN, 2]}, NaN); +testOp({$pow: [1 / 2, NaN]}, NaN); +testOp({$pow: [NaN, NumberDecimal(2)]}, NumberDecimal("NaN")); +testOp({$pow: [NumberDecimal("0.5"), NaN]}, NumberDecimal("NaN")); +testOp({$exp: [NaN]}, NaN); + +// Invalid inputs - non-numeric/non-null types, or 0 to a negative exponent. +assertErrorCode(coll, [{$project: {pow: {$pow: [0, NumberLong("-1")]}}}], 28764); +assertErrorCode(coll, [{$project: {pow: {$pow: ["string", 5]}}}], 28762); +assertErrorCode(coll, [{$project: {pow: {$pow: [5, "string"]}}}], 28763); +assertErrorCode(coll, [{$project: {exp: {$exp: ["string"]}}}], 28765); +assertErrorCode(coll, [{$project: {pow: {$pow: [NumberDecimal(0), NumberLong("-1")]}}}], 28764); +assertErrorCode(coll, [{$project: {pow: {$pow: ["string", NumberDecimal(5)]}}}], 28762); +}()); diff --git a/jstests/aggregation/bugs/server6570.js b/jstests/aggregation/bugs/server6570.js index 1d0b6338b43..112feb49406 100644 --- a/jstests/aggregation/bugs/server6570.js +++ b/jstests/aggregation/bugs/server6570.js @@ -6,19 +6,10 @@ c = db.s6570; c.drop(); c.save({x: 17, y: "foo"}); -// 16554 was the code used instead of TypeMismatch before 6.0. -assertErrorCode( - c, {$project: {string_fields: {$add: [3, "$y", 4, "$y"]}}}, [16554, ErrorCodes.TypeMismatch]); -assertErrorCode(c, - {$project: {number_fields: {$add: ["a", "$x", "b", "$x"]}}}, - [16554, ErrorCodes.TypeMismatch]); -assertErrorCode( - c, {$project: {all_strings: {$add: ["c", "$y", "d", "$y"]}}}, [16554, ErrorCodes.TypeMismatch]); -assertErrorCode( - c, {$project: {potpourri_1: {$add: [5, "$y", "e", "$x"]}}}, [16554, ErrorCodes.TypeMismatch]); -assertErrorCode( - c, {$project: {potpourri_2: {$add: [6, "$x", "f", "$y"]}}}, [16554, ErrorCodes.TypeMismatch]); -assertErrorCode( - c, {$project: {potpourri_3: {$add: ["g", "$y", 7, "$x"]}}}, [16554, ErrorCodes.TypeMismatch]); -assertErrorCode( - c, {$project: {potpourri_4: {$add: ["h", "$x", 8, "$y"]}}}, [16554, ErrorCodes.TypeMismatch]);
\ No newline at end of file +assertErrorCode(c, {$project: {string_fields: {$add: [3, "$y", 4, "$y"]}}}, 16554); +assertErrorCode(c, {$project: {number_fields: {$add: ["a", "$x", "b", "$x"]}}}, 16554); +assertErrorCode(c, {$project: {all_strings: {$add: ["c", "$y", "d", "$y"]}}}, 16554); +assertErrorCode(c, {$project: {potpourri_1: {$add: [5, "$y", "e", "$x"]}}}, 16554); +assertErrorCode(c, {$project: {potpourri_2: {$add: [6, "$x", "f", "$y"]}}}, 16554); +assertErrorCode(c, {$project: {potpourri_3: {$add: ["g", "$y", 7, "$x"]}}}, 16554); +assertErrorCode(c, {$project: {potpourri_4: {$add: ["h", "$x", 8, "$y"]}}}, 16554); diff --git a/jstests/aggregation/bugs/server72651.js b/jstests/aggregation/bugs/server72651.js deleted file mode 100644 index b4100bdc32c..00000000000 --- a/jstests/aggregation/bugs/server72651.js +++ /dev/null @@ -1,12 +0,0 @@ -// SERVER-72651 $match filter is erroneously pushed past $project into COLLSCAN -(function() { - -const c = db.server72651; - -c.drop(); -assert.commandWorked(c.insert({_id: 0, a: 1})); -// The bug caused the query below to return {"_id" : 0} instead of no documents. -assert.eq( - [], - c.aggregate([{$project: {"b": 1}}, {$match: {$expr: {$getField: {$literal: "a"}}}}]).toArray()); -})();
\ No newline at end of file diff --git a/jstests/aggregation/bugs/timeseries_should_not_push_match_before_project.js b/jstests/aggregation/bugs/timeseries_should_not_push_match_before_project.js deleted file mode 100644 index f2465988f0e..00000000000 --- a/jstests/aggregation/bugs/timeseries_should_not_push_match_before_project.js +++ /dev/null @@ -1,30 +0,0 @@ -// Regression test for SERVER-71270. -(function() { -"use strict"; -load('jstests/aggregation/extras/utils.js'); // For assertArrayEq. -const doc = { - _id: 0, - time: new Date('2019-01-18T13:24:15.443Z'), - tag: {}, -}; - -db.ts.drop(); -db.coll.drop(); - -db.createCollection('ts', {timeseries: {timeField: 'time', metaField: 'tag'}}); -db.createCollection('coll'); - -db.ts.insertOne(doc); -db.coll.insertOne(doc); -const pipeline = [ - {$project: {'time': 0}}, - {$match: {'time': {$lte: new Date('2019-02-13T11:36:03.481Z')}}}, -]; - -const ts = db.ts.aggregate(pipeline).toArray(); -const vanilla = db.coll.aggregate(pipeline).toArray(); -assertArrayEq({ - actual: ts, - expected: vanilla, -}); -}()); diff --git a/jstests/aggregation/bugs/window_inside_facet.js b/jstests/aggregation/bugs/window_inside_facet.js deleted file mode 100644 index baf9fcd5150..00000000000 --- a/jstests/aggregation/bugs/window_inside_facet.js +++ /dev/null @@ -1,77 +0,0 @@ -// Test that $setWindowFields inside $facet correctly propagates its state when it encounters paused -// execution. -(function() { -"use strict"; - -const coll = db.window_inside_facet; -coll.drop(); - -assert.commandWorked(coll.insert([ - {_id: 'a', n: 0}, - {_id: 'b', n: 1}, - {_id: 'c', n: 2}, - {_id: 'd', n: 3}, - {_id: 'e', n: 4}, - {_id: 'f', n: 5} -])); - -// Test window with a sort within $facet alongside another pipeline that will cause it to pause -// execution. The sort will cause the window to hit paused execution immediately, before an advance. -let result = - coll.aggregate({ - $facet: { - facet1: [{ - $setWindowFields: { - output: {prevId: {$shift: {by: -1, default: null, output: "$_id"}}}, - sortBy: {_id: 1} - } - }], - facet2: [{$count: "count"}] - } - }) - .toArray()[0]; -let expected = { - facet1: [ - {_id: 'a', n: 0, prevId: null}, - {_id: 'b', n: 1, prevId: 'a'}, - {_id: 'c', n: 2, prevId: 'b'}, - {_id: 'd', n: 3, prevId: 'c'}, - {_id: 'e', n: 4, prevId: 'd'}, - {_id: 'f', n: 5, prevId: 'e'} - ], - facet2: [{count: 6}] -}; -assert.docEq(expected, result, "$setWindowFields with sort failed."); - -// Test window with no sort within $facet alongside another pipeline that will cause it to pause -// execution. Having no sort will cause the window to hit paused execution after advancing. -result = coll.aggregate({ - $facet: { - facet1: [ - { - $setWindowFields: { - output: { - min: {$min: "$n"}, - max: {$max: "$n"}, - } - } - }, - {$sort: {_id: 1}} - ], - facet2: [{$count: "count"}] - } - }) - .toArray()[0]; -expected = { - facet1: [ - {_id: 'a', n: 0, min: 0, max: 5}, - {_id: 'b', n: 1, min: 0, max: 5}, - {_id: 'c', n: 2, min: 0, max: 5}, - {_id: 'd', n: 3, min: 0, max: 5}, - {_id: 'e', n: 4, min: 0, max: 5}, - {_id: 'f', n: 5, min: 0, max: 5} - ], - facet2: [{count: 6}] -}; -assert.docEq(expected, result, "$setWindowFields without sort failed."); -}()); |
