summaryrefslogtreecommitdiff
path: root/jstests/aggregation/bugs
diff options
context:
space:
mode:
authorKyle Suarez <kyle.suarez@mongodb.com>2017-12-14 14:09:13 -0500
committerKyle Suarez <kyle.suarez@mongodb.com>2017-12-14 14:13:26 -0500
commit47247293f18ea581954f6fcf4c0018b7828e3c3a (patch)
treecd5572f377474ecf35baaaf8c4e194d66611a860 /jstests/aggregation/bugs
parentf4c11f679de3781ae202511fe07144e357c80e2b (diff)
downloadmongo-47247293f18ea581954f6fcf4c0018b7828e3c3a.tar.gz
SERVER-31785 use multiple shards in aggregation_sharded_collections_passthrough
Diffstat (limited to 'jstests/aggregation/bugs')
-rw-r--r--jstests/aggregation/bugs/cond.js138
-rw-r--r--jstests/aggregation/bugs/firstlast.js225
-rw-r--r--jstests/aggregation/bugs/server10176.js2
-rw-r--r--jstests/aggregation/bugs/server11675.js182
-rw-r--r--jstests/aggregation/bugs/server12015.js34
-rw-r--r--jstests/aggregation/bugs/server17943.js10
-rw-r--r--jstests/aggregation/bugs/server4588.js24
-rw-r--r--jstests/aggregation/bugs/server4899.js16
-rw-r--r--jstests/aggregation/bugs/server5012.js19
-rw-r--r--jstests/aggregation/bugs/server6127.js57
-rw-r--r--jstests/aggregation/bugs/server6147.js84
-rw-r--r--jstests/aggregation/bugs/server6185.js25
-rw-r--r--jstests/aggregation/bugs/server6779.js27
-rw-r--r--jstests/aggregation/bugs/sort_arrays.js9
14 files changed, 432 insertions, 420 deletions
diff --git a/jstests/aggregation/bugs/cond.js b/jstests/aggregation/bugs/cond.js
index c48c6b724f0..313316f4418 100644
--- a/jstests/aggregation/bugs/cond.js
+++ b/jstests/aggregation/bugs/cond.js
@@ -1,82 +1,88 @@
// $cond returns the evaluated second argument if the first evaluates to true but the evaluated
// third argument if the first evaluates to false.
-load('jstests/aggregation/extras/utils.js');
+(function() {
+ "use strict";
+ load('jstests/aggregation/extras/utils.js');
-t = db.jstests_aggregation_cond;
-t.drop();
+ const coll = db.jstests_aggregation_cond;
+ coll.drop();
-t.save({});
+ coll.save({});
-function assertError(expectedErrorCode, condSpec) {
- assertErrorCode(t, {$project: {a: {$cond: condSpec}}}, expectedErrorCode);
-}
+ function assertError(expectedErrorCode, condSpec) {
+ assertErrorCode(coll, {$project: {a: {$cond: condSpec}}}, expectedErrorCode);
+ }
-function assertResult(expectedResult, arg) {
- assert.eq(expectedResult, t.aggregate({$project: {a: {$cond: arg}}}).toArray()[0].a);
-}
+ function assertResult(expectedResult, arg) {
+ assert.eq(expectedResult, coll.aggregate({$project: {a: {$cond: arg}}}).toArray()[0].a);
+ }
-// Wrong number of args.
-assertError(16020, []);
-assertError(16020, [1]);
-assertError(16020, [false]);
-assertError(16020, [1, 1]);
-assertError(16020, [1, 1, null, 1]);
-assertError(16020, [1, 1, 1, undefined]);
+ // Wrong number of args.
+ assertError(16020, []);
+ assertError(16020, [1]);
+ assertError(16020, [false]);
+ assertError(16020, [1, 1]);
+ assertError(16020, [1, 1, null, 1]);
+ assertError(16020, [1, 1, 1, undefined]);
-// Bad object cases
-assertError(17080, {"else": 1, then: 1});
-assertError(17081, {"if": 1, "else": 1});
-assertError(17082, {"if": 1, then: 1});
-assertError(17083, {asdf: 1, then: 1});
+ // Bad object cases.
+ assertError(17080, {"else": 1, then: 1});
+ assertError(17081, {"if": 1, "else": 1});
+ assertError(17082, {"if": 1, then: 1});
+ assertError(17083, {asdf: 1, then: 1});
-// Literal expressions.
-assertResult(1, [true, 1, 2]);
-assertResult(2, [false, 1, 2]);
+ // Literal expressions.
+ assertResult(1, [true, 1, 2]);
+ assertResult(2, [false, 1, 2]);
-// Order independence for object case
-assertResult(1, {"if": true, "then": 1, "else": 2});
-assertResult(1, {"if": true, "else": 2, "then": 1});
-assertResult(1, {"then": 1, "if": true, "else": 2});
-assertResult(1, {"then": 1, "else": 2, "if": true});
-assertResult(1, {"else": 2, "then": 1, "if": true});
-assertResult(1, {"else": 2, "if": true, "then": 1});
+ // Order independence for object case.
+ assertResult(1, {"if": true, "then": 1, "else": 2});
+ assertResult(1, {"if": true, "else": 2, "then": 1});
+ assertResult(1, {"then": 1, "if": true, "else": 2});
+ assertResult(1, {"then": 1, "else": 2, "if": true});
+ assertResult(1, {"else": 2, "then": 1, "if": true});
+ assertResult(1, {"else": 2, "if": true, "then": 1});
-// Computed expressions.
-assertResult(1, [{$and: []}, {$add: [1]}, {$add: [1, 1]}]);
-assertResult(2, [{$or: []}, {$add: [1]}, {$add: [1, 1]}]);
+ // Computed expressions.
+ assertResult(1, [{$and: []}, {$add: [1]}, {$add: [1, 1]}]);
+ assertResult(2, [{$or: []}, {$add: [1]}, {$add: [1, 1]}]);
-t.drop();
-t.save({t: true, f: false, x: 'foo', y: 'bar'});
+ assert(coll.drop());
+ assert.writeOK(coll.insert({t: true, f: false, x: 'foo', y: 'bar'}));
-// Field path expressions.
-assertResult('foo', ['$t', '$x', '$y']);
-assertResult('bar', ['$f', '$x', '$y']);
+ // Field path expressions.
+ assertResult('foo', ['$t', '$x', '$y']);
+ assertResult('bar', ['$f', '$x', '$y']);
-t.drop();
-t.save({});
+ assert(coll.drop());
+ assert.writeOK(coll.insert({}));
-// Coerce to bool.
-assertResult('a', [1, 'a', 'b']);
-assertResult('a', ['', 'a', 'b']);
-assertResult('b', [0, 'a', 'b']);
+ // Coerce to bool.
+ assertResult('a', [1, 'a', 'b']);
+ assertResult('a', ['', 'a', 'b']);
+ assertResult('b', [0, 'a', 'b']);
-// Nested.
-t.drop();
-t.save({noonSense: 'am', mealCombined: 'no'});
-t.save({noonSense: 'am', mealCombined: 'yes'});
-t.save({noonSense: 'pm', mealCombined: 'yes'});
-t.save({noonSense: 'pm', mealCombined: 'no'});
-assert.eq(['breakfast', 'brunch', 'linner', 'dinner'],
- t.aggregate({
- $project: {
- a: {
- $cond: [
- {$eq: ['$noonSense', 'am']},
- {$cond: [{$eq: ['$mealCombined', 'yes']}, 'brunch', 'breakfast']},
- {$cond: [{$eq: ['$mealCombined', 'yes']}, 'linner', 'dinner']}
- ]
- }
- }
- }).map(function(x) {
- return x.a;
- }));
+ // Nested.
+ assert(coll.drop());
+ assert.writeOK(coll.insert({noonSense: 'am', mealCombined: 'no'}));
+ assert.writeOK(coll.insert({noonSense: 'am', mealCombined: 'yes'}));
+ assert.writeOK(coll.insert({noonSense: 'pm', mealCombined: 'yes'}));
+ assert.writeOK(coll.insert({noonSense: 'pm', mealCombined: 'no'}));
+ assert.eq(
+ ['breakfast', 'brunch', 'dinner', 'linner'],
+ coll.aggregate([
+ {
+ $project: {
+ meal: {
+ $cond: [
+ {$eq: ['$noonSense', 'am']},
+ {$cond: [{$eq: ['$mealCombined', 'yes']}, 'brunch', 'breakfast']},
+ {$cond: [{$eq: ['$mealCombined', 'yes']}, 'linner', 'dinner']}
+ ]
+ }
+ }
+ },
+ {$sort: {meal: 1}}
+ ])
+ .map(doc => doc.meal));
+}());
diff --git a/jstests/aggregation/bugs/firstlast.js b/jstests/aggregation/bugs/firstlast.js
index 54f0f8be0e9..aa360a25b7e 100644
--- a/jstests/aggregation/bugs/firstlast.js
+++ b/jstests/aggregation/bugs/firstlast.js
@@ -1,108 +1,121 @@
-// Check $first/$last group accumulators. SERVER-3862
-// $first/$last select first/last value for a group key from the previous pipeline.
-
-t = db.jstests_aggregation_firstlast;
-t.drop();
-
-/** Check expected $first and $last result values. */
-function assertFirstLast(expectedFirst, expectedLast, pipeline, expression) {
- pipeline = pipeline || [];
- expression = expression || '$b';
- pipeline.push({$group: {_id: '$a', first: {$first: expression}, last: {$last: expression}}});
- result = t.aggregate(pipeline).toArray();
- for (var 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;
+/**
+ * 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);
+ }
+
+ 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');
}
- assert(false, "Expected group _id '1' missing.");
-}
-
-// One document.
-t.save({a: 1, b: 1});
-assertFirstLast(1, 1);
-
-// Two documents.
-t.save({a: 1, b: 2});
-assertFirstLast(1, 2);
-
-// Three documents.
-t.save({a: 1, b: 3});
-assertFirstLast(1, 3);
-
-// Another 'a' key value does not affect outcome.
-t.drop();
-t.save({a: 3, b: 0});
-t.save({a: 1, b: 1});
-t.save({a: 1, b: 2});
-t.save({a: 1, b: 3});
-t.save({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.
-t.drop();
-t.save({a: 1, b: 1});
-t.save({a: 1, b: 2});
-t.save({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.
-t.save({a: 1, b: 'foo'});
-assertFirstLast(1, 'foo');
-
-t.drop();
-t.save({a: 1, b: 'bar'});
-t.save({a: 1, b: true});
-assertFirstLast('bar', true);
-
-// Value null.
-t.drop();
-t.save({a: 1, b: null});
-t.save({a: 1, b: 2});
-assertFirstLast(null, 2);
-t.drop();
-t.save({a: 1, b: 2});
-t.save({a: 1, b: null});
-assertFirstLast(2, null);
-t.drop();
-t.save({a: 1, b: null});
-t.save({a: 1, b: null});
-assertFirstLast(null, null);
-
-// Value missing.
-t.drop();
-t.save({a: 1});
-t.save({a: 1, b: 2});
-assertFirstLast(undefined, 2);
-t.drop();
-t.save({a: 1, b: 2});
-t.save({a: 1});
-assertFirstLast(2, undefined);
-t.drop();
-t.save({a: 1});
-t.save({a: 1});
-assertFirstLast(undefined, undefined);
-
-// Dotted field.
-t.drop();
-t.save({a: 1, b: [{c: 1}, {c: 2}]});
-t.save({a: 1, b: [{c: 6}, {}]});
-assertFirstLast([1, 2], [6], [], '$b.c');
-
-// Computed expressions.
-t.drop();
-t.save({a: 1, b: 1});
-t.save({a: 1, b: 2});
-assertFirstLast(1, 0, [], {$mod: ['$b', 2]});
-assertFirstLast(0, 1, [], {$mod: [{$add: ['$b', 1]}, 2]});
+
+ // 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]});
+}());
diff --git a/jstests/aggregation/bugs/server10176.js b/jstests/aggregation/bugs/server10176.js
index b04db0c4319..988beb24f13 100644
--- a/jstests/aggregation/bugs/server10176.js
+++ b/jstests/aggregation/bugs/server10176.js
@@ -32,7 +32,7 @@ load('jstests/aggregation/extras/utils.js');
// valid use of $abs: numbers become positive, null/undefined/nonexistent become null
- var results = coll.aggregate([{$project: {a: {$abs: "$a"}}}]).toArray();
+ var results = coll.aggregate([{$project: {a: {$abs: "$a"}}}, {$sort: {_id: 1}}]).toArray();
assert.eq(results, [
{_id: 0, a: 5},
{_id: 1, a: 5},
diff --git a/jstests/aggregation/bugs/server11675.js b/jstests/aggregation/bugs/server11675.js
index c80f9a38af5..ee677aa085a 100644
--- a/jstests/aggregation/bugs/server11675.js
+++ b/jstests/aggregation/bugs/server11675.js
@@ -1,28 +1,29 @@
// SERVER-11675 Text search integration with aggregation
load('jstests/aggregation/extras/utils.js');
-var server11675 = function() {
- var t = db.server11675;
- t.drop();
+const server11675 = function() {
+ const coll = db.server11675;
+ coll.drop();
if (typeof(RUNNING_IN_SHARDED_AGG_TEST) != 'undefined') { // see end of testshard1.js
- db.adminCommand({shardcollection: t.getFullName(), key: {"_id": 1}});
+ assert.commandWorked(
+ db.adminCommand({shardcollection: coll.getFullName(), key: {"_id": 1}}));
}
- t.insert({_id: 1, text: "apple", words: 1});
- t.insert({_id: 2, text: "banana", words: 1});
- t.insert({_id: 3, text: "apple banana", words: 2});
- t.insert({_id: 4, text: "cantaloupe", words: 1});
+ assert.writeOK(coll.insert({_id: 1, text: "apple", words: 1}));
+ assert.writeOK(coll.insert({_id: 2, text: "banana", words: 1}));
+ assert.writeOK(coll.insert({_id: 3, text: "apple banana", words: 2}));
+ assert.writeOK(coll.insert({_id: 4, text: "cantaloupe", words: 1}));
- t.ensureIndex({text: "text"});
+ assert.commandWorked(coll.createIndex({text: "text"}));
// query should have subfields query, project, sort, skip and limit. All but query are optional.
- var assertSameAsFind = function(query) {
- var cursor = t.find(query.query);
- var pipeline = [{$match: query.query}];
+ const assertSameAsFind = function(query) {
+ let cursor = coll.find(query.query);
+ const pipeline = [{$match: query.query}];
if ('project' in query) {
- cursor = t.find(query.query, query.project); // no way to add to constructed cursor
+ cursor = coll.find(query.query, query.project); // no way to add to constructed cursor
pipeline.push({$project: query.project});
}
@@ -41,8 +42,8 @@ var server11675 = function() {
pipeline.push({$limit: query.limit});
}
- var findRes = cursor.toArray();
- var aggRes = t.aggregate(pipeline).toArray();
+ const findRes = cursor.toArray();
+ const aggRes = coll.aggregate(pipeline).toArray();
// If the query doesn't specify its own sort, there is a possibility that find() and
// aggregate() will return the same results in different orders. We sort by _id on the
@@ -95,128 +96,137 @@ var server11675 = function() {
// $meta sort specification should be rejected if it has additional keys.
assert.throws(function() {
- t.aggregate([
- {$match: {$text: {$search: 'apple banana'}}},
- {$sort: {textScore: {$meta: 'textScore', extra: 1}}}
- ]).itcount();
+ coll.aggregate([
+ {$match: {$text: {$search: 'apple banana'}}},
+ {$sort: {textScore: {$meta: 'textScore', extra: 1}}}
+ ])
+ .itcount();
});
// $meta sort specification should be rejected if the type of meta sort is not known.
assert.throws(function() {
- t.aggregate([
- {$match: {$text: {$search: 'apple banana'}}},
- {$sort: {textScore: {$meta: 'unknown'}}}
- ]).itcount();
+ coll.aggregate([
+ {$match: {$text: {$search: 'apple banana'}}},
+ {$sort: {textScore: {$meta: 'unknown'}}}
+ ])
+ .itcount();
});
// Sort specification should be rejected if a $-keyword other than $meta is used.
assert.throws(function() {
- t.aggregate([
- {$match: {$text: {$search: 'apple banana'}}},
- {$sort: {textScore: {$notMeta: 'textScore'}}}
- ]).itcount();
+ coll.aggregate([
+ {$match: {$text: {$search: 'apple banana'}}},
+ {$sort: {textScore: {$notMeta: 'textScore'}}}
+ ])
+ .itcount();
});
// Sort specification should be rejected if it is a string, not an object with $meta.
assert.throws(function() {
- t.aggregate([
- {$match: {$text: {$search: 'apple banana'}}},
- {$sort: {textScore: 'textScore'}}
- ]).itcount();
+ coll.aggregate(
+ [{$match: {$text: {$search: 'apple banana'}}}, {$sort: {textScore: 'textScore'}}])
+ .itcount();
});
// sharded find requires projecting the score to sort, but sharded agg does not.
- var findRes = t.find({$text: {$search: "apple banana"}}, {textScore: {$meta: 'textScore'}})
+ var findRes = coll.find({$text: {$search: "apple banana"}}, {textScore: {$meta: 'textScore'}})
.sort({textScore: {$meta: 'textScore'}})
.map(function(obj) {
delete obj.textScore; // remove it to match agg output
return obj;
});
- var res = t.aggregate([
- {$match: {$text: {$search: 'apple banana'}}},
- {$sort: {textScore: {$meta: 'textScore'}}}
- ]).toArray();
+ let res = coll.aggregate([
+ {$match: {$text: {$search: 'apple banana'}}},
+ {$sort: {textScore: {$meta: 'textScore'}}}
+ ])
+ .toArray();
assert.eq(res, findRes);
// Make sure {$meta: 'textScore'} can be used as a sub-expression
- var res = t.aggregate([
- {$match: {_id: 1, $text: {$search: 'apple'}}},
- {
- $project: {
- words: 1,
- score: {$meta: 'textScore'},
- wordsTimesScore: {$multiply: ['$words', {$meta: 'textScore'}]}
- }
- }
- ]).toArray();
+ res = coll.aggregate([
+ {$match: {_id: 1, $text: {$search: 'apple'}}},
+ {
+ $project: {
+ words: 1,
+ score: {$meta: 'textScore'},
+ wordsTimesScore: {$multiply: ['$words', {$meta: 'textScore'}]}
+ }
+ }
+ ])
+ .toArray();
assert.eq(res[0].wordsTimesScore, res[0].words * res[0].score, tojson(res));
// And can be used in $group
- var res = t.aggregate([
- {$match: {_id: 1, $text: {$search: 'apple banana'}}},
- {$group: {_id: {$meta: 'textScore'}, score: {$first: {$meta: 'textScore'}}}}
- ]).toArray();
+ res = coll.aggregate([
+ {$match: {_id: 1, $text: {$search: 'apple banana'}}},
+ {$group: {_id: {$meta: 'textScore'}, score: {$first: {$meta: 'textScore'}}}}
+ ])
+ .toArray();
assert.eq(res[0]._id, res[0].score, tojson(res));
// Make sure metadata crosses shard -> merger boundary
- var res = t.aggregate([
- {$match: {_id: 1, $text: {$search: 'apple'}}},
- {$project: {scoreOnShard: {$meta: 'textScore'}}},
- {$limit: 1} // force a split. later stages run on merger
- ,
- {$project: {scoreOnShard: 1, scoreOnMerger: {$meta: 'textScore'}}}
- ]).toArray();
+ res = coll.aggregate([
+ {$match: {_id: 1, $text: {$search: 'apple'}}},
+ {$project: {scoreOnShard: {$meta: 'textScore'}}},
+ {$limit: 1}, // force a split. later stages run on merger
+ {$project: {scoreOnShard: 1, scoreOnMerger: {$meta: 'textScore'}}}
+ ])
+ .toArray();
assert.eq(res[0].scoreOnMerger, res[0].scoreOnShard);
- var score = res[0].scoreOnMerger; // save for later tests
+ let score = res[0].scoreOnMerger; // save for later tests
// Make sure metadata crosses shard -> merger boundary even if not used on shard
- var res = t.aggregate([
- {$match: {_id: 1, $text: {$search: 'apple'}}},
- {$limit: 1} // force a split. later stages run on merger
- ,
- {$project: {scoreOnShard: 1, scoreOnMerger: {$meta: 'textScore'}}}
- ]).toArray();
+ res = coll.aggregate([
+ {$match: {_id: 1, $text: {$search: 'apple'}}},
+ {$limit: 1}, // force a split. later stages run on merger
+ {$project: {scoreOnShard: 1, scoreOnMerger: {$meta: 'textScore'}}}
+ ])
+ .toArray();
assert.eq(res[0].scoreOnMerger, score);
// Make sure metadata works if first $project doesn't use it.
- var res = t.aggregate([
- {$match: {_id: 1, $text: {$search: 'apple'}}},
- {$project: {_id: 1}},
- {$project: {_id: 1, score: {$meta: 'textScore'}}}
- ]).toArray();
+ res = coll.aggregate([
+ {$match: {_id: 1, $text: {$search: 'apple'}}},
+ {$project: {_id: 1}},
+ {$project: {_id: 1, score: {$meta: 'textScore'}}}
+ ])
+ .toArray();
assert.eq(res[0].score, score);
// Make sure the pipeline fails if it tries to reference the text score and it doesn't exist.
- var res = t.runCommand(
- {aggregate: t.getName(), pipeline: [{$project: {_id: 1, score: {$meta: 'textScore'}}}]});
+ res = coll.runCommand(
+ {aggregate: coll.getName(), pipeline: [{$project: {_id: 1, score: {$meta: 'textScore'}}}]});
assert.commandFailed(res);
// Make sure the metadata is 'missing()' when it doesn't exist because the document changed
- var res = t.aggregate([
- {$match: {_id: 1, $text: {$search: 'apple banana'}}},
- {$group: {_id: 1, score: {$first: {$meta: 'textScore'}}}},
- {$project: {_id: 1, scoreAgain: {$meta: 'textScore'}}},
- ]).toArray();
+ res = coll.aggregate([
+ {$match: {_id: 1, $text: {$search: 'apple banana'}}},
+ {$group: {_id: 1, score: {$first: {$meta: 'textScore'}}}},
+ {$project: {_id: 1, scoreAgain: {$meta: 'textScore'}}},
+ ])
+ .toArray();
assert(!("scoreAgain" in res[0]));
// Make sure metadata works after a $unwind
- t.insert({_id: 5, text: 'mango', words: [1, 2, 3]});
- var res = t.aggregate([
- {$match: {$text: {$search: 'mango'}}},
- {$project: {score: {$meta: "textScore"}, _id: 1, words: 1}},
- {$unwind: '$words'},
- {$project: {scoreAgain: {$meta: "textScore"}, score: 1}}
- ]).toArray();
+ assert.writeOK(coll.insert({_id: 5, text: 'mango', words: [1, 2, 3]}));
+ res = coll.aggregate([
+ {$match: {$text: {$search: 'mango'}}},
+ {$project: {score: {$meta: "textScore"}, _id: 1, words: 1}},
+ {$unwind: '$words'},
+ {$project: {scoreAgain: {$meta: "textScore"}, score: 1}}
+ ])
+ .toArray();
assert.eq(res[0].scoreAgain, res[0].score);
// Error checking
// $match, but wrong position
- assertErrorCode(t, [{$sort: {text: 1}}, {$match: {$text: {$search: 'apple banana'}}}], 17313);
+ assertErrorCode(
+ coll, [{$sort: {text: 1}}, {$match: {$text: {$search: 'apple banana'}}}], 17313);
// wrong $stage, but correct position
- assertErrorCode(t,
+ assertErrorCode(coll,
[{$project: {searchValue: {$text: {$search: 'apple banana'}}}}],
ErrorCodes.InvalidPipelineOperator);
- assertErrorCode(t, [{$sort: {$text: {$search: 'apple banana'}}}], 17312);
+ assertErrorCode(coll, [{$sort: {$text: {$search: 'apple banana'}}}], 17312);
};
server11675();
diff --git a/jstests/aggregation/bugs/server12015.js b/jstests/aggregation/bugs/server12015.js
index c237e4f6f90..150ff30e708 100644
--- a/jstests/aggregation/bugs/server12015.js
+++ b/jstests/aggregation/bugs/server12015.js
@@ -10,9 +10,9 @@ load("jstests/aggregation/extras/utils.js"); // For orderedArrayEq.
(function() {
"use strict";
- var coll = db.server12015;
+ const coll = db.server12015;
coll.drop();
- var indexSpec = {a: 1, b: 1};
+ const indexSpec = {a: 1, b: 1};
assert.writeOK(coll.insert({_id: 0, a: 0, b: 0}));
assert.writeOK(coll.insert({_id: 1, a: 0, b: 1}));
@@ -21,10 +21,11 @@ load("jstests/aggregation/extras/utils.js"); // For orderedArrayEq.
/**
* Helper to test that for a given pipeline, the same results are returned whether or not an
- * index is present.
+ * index is present. If 'ignoreSortOrder' is present, test for result parity without assuming
+ * the order of results.
*/
- function assertResultsMatch(pipeline) {
- // Add a match stage to ensure index scans are considerd for planning (workaround for
+ function assertResultsMatch(pipeline, ignoreSortOrder) {
+ // Add a match stage to ensure index scans are considered for planning (workaround for
// SERVER-20066).
pipeline = [{$match: {a: {$gte: 0}}}].concat(pipeline);
@@ -36,18 +37,27 @@ load("jstests/aggregation/extras/utils.js"); // For orderedArrayEq.
assert.commandWorked(coll.dropIndex(indexSpec));
var resultsWithoutIndex = coll.aggregate(pipeline).toArray();
- assert(orderedArrayEq(resultsWithIndex, resultsWithoutIndex));
+ if (ignoreSortOrder) {
+ assert(arrayEq(resultsWithIndex, resultsWithoutIndex), tojson({
+ resultsWithIndex: resultsWithIndex,
+ resultsWithoutIndex: resultsWithoutIndex
+ }));
+ } else {
+ assert.eq(resultsWithIndex, resultsWithoutIndex);
+ }
}
// Uncovered $project, no $sort.
- assertResultsMatch([{$project: {_id: 1, a: 1, b: 1}}]);
+ const ignoreSortOrder = true;
+ assertResultsMatch([{$project: {_id: 1, a: 1, b: 1}}], ignoreSortOrder);
// Covered $project, no $sort.
- assertResultsMatch([{$project: {_id: 0, a: 1}}]);
- assertResultsMatch([{$project: {_id: 0, a: 1, b: 1}}]);
- assertResultsMatch([{$project: {_id: 0, a: 1, b: 1, c: {$literal: 1}}}]);
- assertResultsMatch([{$project: {_id: 0, a: 1, b: 1}}, {$project: {a: 1}}]);
- assertResultsMatch([{$project: {_id: 0, a: 1, b: 1}}, {$group: {_id: null, a: {$sum: "$a"}}}]);
+ assertResultsMatch([{$project: {_id: 0, a: 1}}], ignoreSortOrder);
+ assertResultsMatch([{$project: {_id: 0, a: 1, b: 1}}], ignoreSortOrder);
+ assertResultsMatch([{$project: {_id: 0, a: 1, b: 1, c: {$literal: 1}}}], ignoreSortOrder);
+ assertResultsMatch([{$project: {_id: 0, a: 1, b: 1}}, {$project: {a: 1}}], ignoreSortOrder);
+ assertResultsMatch([{$project: {_id: 0, a: 1, b: 1}}, {$group: {_id: null, a: {$sum: "$a"}}}],
+ ignoreSortOrder);
// Non-blocking $sort, uncovered $project.
assertResultsMatch([{$sort: {a: -1, b: -1}}, {$project: {_id: 1, a: 1, b: 1}}]);
diff --git a/jstests/aggregation/bugs/server17943.js b/jstests/aggregation/bugs/server17943.js
index 35d67d4fe20..075623c705d 100644
--- a/jstests/aggregation/bugs/server17943.js
+++ b/jstests/aggregation/bugs/server17943.js
@@ -28,7 +28,8 @@ load('jstests/aggregation/extras/utils.js');
{_id: 5, b: null},
{_id: 6, b: null},
];
- var results = coll.aggregate([{$project: {b: {$filter: filterDoc}}}]).toArray();
+ var results =
+ coll.aggregate([{$project: {b: {$filter: filterDoc}}}, {$sort: {_id: 1}}]).toArray();
assert.eq(results, expectedResults);
// create filter that uses the default variable name in 'cond'
@@ -42,14 +43,11 @@ load('jstests/aggregation/extras/utils.js');
{_id: 5, b: null},
{_id: 6, b: null},
];
- results = coll.aggregate([{$project: {b: {$filter: filterDoc}}}]).toArray();
+ results = coll.aggregate([{$project: {b: {$filter: filterDoc}}}, {$sort: {_id: 1}}]).toArray();
assert.eq(results, expectedResults);
// Invalid filter expressions.
- // Insert a document so that the initial cursor doesn't immediately return EOF.
- coll.insert({_id: 0, a: [1, 2]});
-
// '$filter' is not a document.
var filterDoc = 'string';
assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 28646);
@@ -78,7 +76,7 @@ load('jstests/aggregation/extras/utils.js');
filterDoc = {input: '$a', cond: {$eq: [1, '$$var']}};
assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 17276);
- coll.drop();
+ assert(coll.drop());
assert.writeOK(coll.insert({a: 'string'}));
filterDoc = {input: '$a', as: 'x', cond: true};
assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 28651);
diff --git a/jstests/aggregation/bugs/server4588.js b/jstests/aggregation/bugs/server4588.js
index 49f41283f6d..000cc8f0231 100644
--- a/jstests/aggregation/bugs/server4588.js
+++ b/jstests/aggregation/bugs/server4588.js
@@ -2,7 +2,7 @@
(function() {
"use strict";
- var coll = db.server4588;
+ const coll = db.server4588;
coll.drop();
assert.writeOK(coll.insert({_id: 0}));
@@ -12,8 +12,9 @@
assert.writeOK(coll.insert({_id: 4, x: 5}));
// Without includeArrayIndex.
- var actualResults = coll.aggregate([{$unwind: {path: "$x"}}]).toArray();
- var expectedResults = [
+ let actualResults =
+ coll.aggregate([{$unwind: {path: "$x"}}, {$sort: {_id: 1, x: 1}}]).toArray();
+ let expectedResults = [
{_id: 3, x: 1},
{_id: 3, x: 2},
{_id: 3, x: 3},
@@ -22,7 +23,10 @@
assert.eq(expectedResults, actualResults, "Incorrect results for normal $unwind");
// With includeArrayIndex, index inserted into a new field.
- actualResults = coll.aggregate([{$unwind: {path: "$x", includeArrayIndex: "index"}}]).toArray();
+ actualResults =
+ coll.aggregate(
+ [{$unwind: {path: "$x", includeArrayIndex: "index"}}, {$sort: {_id: 1, x: 1}}])
+ .toArray();
expectedResults = [
{_id: 3, x: 1, index: NumberLong(0)},
{_id: 3, x: 2, index: NumberLong(1)},
@@ -32,12 +36,14 @@
assert.eq(expectedResults, actualResults, "Incorrect results $unwind with includeArrayIndex");
// With both includeArrayIndex and preserveNullAndEmptyArrays.
- // TODO: update this test when SERVER-20168 is resolved.
actualResults =
- coll.aggregate([{
- $unwind:
- {path: "$x", includeArrayIndex: "index", preserveNullAndEmptyArrays: true}
- }])
+ coll.aggregate([
+ {
+ $unwind:
+ {path: "$x", includeArrayIndex: "index", preserveNullAndEmptyArrays: true}
+ },
+ {$sort: {_id: 1, x: 1}}
+ ])
.toArray();
expectedResults = [
{_id: 0, index: null},
diff --git a/jstests/aggregation/bugs/server4899.js b/jstests/aggregation/bugs/server4899.js
deleted file mode 100644
index b90ed984c2a..00000000000
--- a/jstests/aggregation/bugs/server4899.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// test $size
-load('jstests/aggregation/extras/utils.js');
-
-c = db.server4899;
-c.drop();
-c.save({arr: []});
-c.save({arr: [1]});
-c.save({arr: ["asdf", "asdfasdf"]});
-c.save({arr: [1, "asdf", 1234, 4.3, {key: 23}]});
-c.save({arr: [3, [31, 31, 13, 13]]});
-
-result = c.aggregate({$project: {_id: 0, length: {$size: "$arr"}}});
-assert.eq(result.toArray(), [{length: 0}, {length: 1}, {length: 2}, {length: 5}, {length: 2}]);
-
-c.save({arr: 231});
-assertErrorCode(c, {$project: {_id: 0, length: {$size: "$arr"}}}, 17124);
diff --git a/jstests/aggregation/bugs/server5012.js b/jstests/aggregation/bugs/server5012.js
index 64f55369dc4..a9955349490 100644
--- a/jstests/aggregation/bugs/server5012.js
+++ b/jstests/aggregation/bugs/server5012.js
@@ -1,12 +1,11 @@
-// use aggdb
-db = db.getSiblingDB("aggdb");
-var article = db.article;
+(function() {
+ "use strict";
+ load('jstests/aggregation/data/articles.js');
-load('jstests/aggregation/data/articles.js');
+ const article = db.getSiblingDB("aggdb").getCollection("article");
+ const cursor = article.aggregate(
+ [{$sort: {_id: 1}}, {$project: {author: 1, _id: 0}}, {$project: {Writer: "$author"}}]);
+ const expected = [{Writer: "bob"}, {Writer: "dave"}, {Writer: "jane"}];
-// original crash from ticket
-var r3 = article.aggregate({$project: {author: 1, _id: 0}}, {$project: {Writer: "$author"}});
-
-var r3result = [{"Writer": "bob"}, {"Writer": "dave"}, {"Writer": "jane"}];
-
-assert.eq(r3.toArray(), r3result, 's5012 failed');
+ assert.eq(cursor.toArray(), expected);
+}());
diff --git a/jstests/aggregation/bugs/server6127.js b/jstests/aggregation/bugs/server6127.js
index f217e9a8d93..26585c87d21 100644
--- a/jstests/aggregation/bugs/server6127.js
+++ b/jstests/aggregation/bugs/server6127.js
@@ -1,44 +1,27 @@
/*
- * SERVER-6127 : $project uasserts if an expected nested field has a non object parent in a document
+ * SERVER-6127 : $project uasserts if an expected nested field has a non object parent in a
+ * document.
*
* This test validates the SERVER-6127 ticket. Return undefined when retrieving a field along a
- * path, when the subpath does not exist (this is what happens when a field does not exist and
- * there is no path). Previous it would uassert causing the aggregation to end.
+ * path, when the subpath does not exist (this is what happens when a field does not exist and there
+ * is no path). Previous it would uassert causing the aggregation to end.
*/
+(function() {
+ "use strict";
+ db.s6127.drop();
-/*
- * 1) Clear and create testing db
- * 2) Run an aggregation that simply projects a two fields, one with a sub path one without
- * 3) Assert that the result is what we expected
- */
-
-// Clear db
-db.s6127.drop();
-
-// Populate db
-db.s6127.save({a: 1});
-db.s6127.save({foo: 2});
-db.s6127.save({foo: {bar: 3}});
-
-// Aggregate checking the field foo and the path foo.bar
-var s6127 = db.s6127.aggregate({$project: {_id: 0, 'foo.bar': 1, field: "$foo", path: "$foo.bar"}});
-
-/*
- * The first document should contain nothing as neither field exists, the second document should
- * contain only field as it has a value in foo, but foo does not have a field bar so it cannot walk
- * that path, the third document should have both the field and path as foo is an object which has
- * a field bar
- */
-var s6127result = [
- {},
- {field: 2},
- {
- foo: {bar: 3},
- field: {bar: 3},
- path: 3
+ assert.writeOK(db.s6127.insert({_id: 0, a: 1}));
+ assert.writeOK(db.s6127.insert({_id: 1, foo: 2}));
+ assert.writeOK(db.s6127.insert({_id: 2, foo: {bar: 3}}));
- }
-];
+ // Aggregate checking the field foo and the path foo.bar.
+ const cursor = db.s6127.aggregate(
+ [{$sort: {_id: 1}}, {$project: {_id: 0, "foo.bar": 1, field: "$foo", path: "$foo.bar"}}]);
-// Assert
-assert.eq(s6127.toArray(), s6127result, 's6127 failed');
+ // The first document should contain nothing as neither field exists, the second document should
+ // contain only field as it has a value in foo, but foo does not have a field bar so it cannot
+ // walk that path, the third document should have both the field and path as foo is an object
+ // which has a field bar.
+ const expected = [{}, {field: 2}, {foo: {bar: 3}, field: {bar: 3}, path: 3}];
+ assert.eq(cursor.toArray(), expected);
+}());
diff --git a/jstests/aggregation/bugs/server6147.js b/jstests/aggregation/bugs/server6147.js
index b376afa3c75..0969b366636 100644
--- a/jstests/aggregation/bugs/server6147.js
+++ b/jstests/aggregation/bugs/server6147.js
@@ -1,55 +1,49 @@
/*
- * SERVER-6147 : aggregation $ne expression applied to constant returns incorrect result
+ * SERVER-6147 : aggregation $ne expression applied to constant returns incorrect result.
*
* This test validates the SERVER-6147 ticket. Return true when comparing a constant to a field
* containing a different value using $ne. Previously it would return false when comparing a
* constant and a field regardless of whether they were equal or not.
*/
+(function() {
+ "use strict";
+ db.s6147.drop();
-/*
- * 1) Clear and create testing db
- * 2) Run an aggregation with $ne comparing constants and fields in various configurations
- * 3) Assert that the result is what we expected
- */
-
-// Clear db
-db.s6147.drop();
+ assert.writeOK(db.s6147.insert({a: 1}));
+ assert.writeOK(db.s6147.insert({a: 2}));
-// Populate db
-db.s6147.save({a: 1});
-db.s6147.save({a: 2});
+ // Aggregate checking various combinations of the constant and the field.
+ const cursor = db.s6147.aggregate([
+ {$sort: {a: 1}},
+ {
+ $project: {
+ _id: 0,
+ constantAndField: {$ne: [1, "$a"]},
+ fieldAndConstant: {$ne: ["$a", 1]},
+ constantAndConstant: {$ne: [1, 1]},
+ fieldAndField: {$ne: ["$a", "$a"]}
+ }
+ }
+ ]);
-// Aggregate checking various combinations of the constant and the field
-var s6147 = db.s6147.aggregate({
- $project: {
- _id: 0,
- constantAndField: {$ne: [1, "$a"]},
- fieldAndConstant: {$ne: ["$a", 1]},
- constantAndConstant: {$ne: [1, 1]},
- fieldAndField: {$ne: ["$a", "$a"]}
- }
-});
-
-/*
- * In both documents the constantAndConstant and fieldAndField should be false since they compare
- * something with itself but the constantAndField and fieldAndConstant should be different as
- * document one contains 1 which should return false and document 2 contains something different so
- * should return true
- */
-var s6147result = [
- {
- constantAndField: false,
- fieldAndConstant: false,
- constantAndConstant: false,
- fieldAndField: false
- },
- {
- constantAndField: true,
- fieldAndConstant: true,
- constantAndConstant: false,
- fieldAndField: false
- }
-];
+ // In both documents, the constantAndConstant and fieldAndField should be false since they
+ // compare something with itself. However, the constantAndField and fieldAndConstant should be
+ // different as document one contains 1 which should return false and document 2 contains
+ // something different so should return true.
+ const expected = [
+ {
+ constantAndField: false,
+ fieldAndConstant: false,
+ constantAndConstant: false,
+ fieldAndField: false
+ },
+ {
+ constantAndField: true,
+ fieldAndConstant: true,
+ constantAndConstant: false,
+ fieldAndField: false
+ }
+ ];
-// Assert
-assert.eq(s6147.toArray(), s6147result, 's6147 failed');
+ assert.eq(cursor.toArray(), expected);
+}());
diff --git a/jstests/aggregation/bugs/server6185.js b/jstests/aggregation/bugs/server6185.js
index e1b19ad2c1f..cf084d4b371 100644
--- a/jstests/aggregation/bugs/server6185.js
+++ b/jstests/aggregation/bugs/server6185.js
@@ -1,12 +1,17 @@
-// projecting a non-existent subfield should work as it does in a query with projection
-c = db.c;
-c.drop();
+/**
+ * Tests that projecting a non-existent subfield behaves identically in both query and aggregation.
+ */
+(function() {
+ "use strict";
+ const coll = db.c;
+ coll.drop();
-c.save({a: [1]});
-c.save({a: {c: 1}});
-c.save({a: [{c: 1}, {b: 1, c: 1}, {c: 1}]});
-c.save({a: 1});
-c.save({b: 1});
+ assert.writeOK(coll.insert({a: [1]}));
+ assert.writeOK(coll.insert({a: {c: 1}}));
+ assert.writeOK(coll.insert({a: [{c: 1}, {b: 1, c: 1}, {c: 1}]}));
+ assert.writeOK(coll.insert({a: 1}));
+ assert.writeOK(coll.insert({b: 1}));
-// assert the aggregation and the query produce the same thing
-assert.eq(c.aggregate({$project: {'a.b': 1}}).toArray(), c.find({}, {'a.b': 1}).toArray());
+ assert.eq(coll.aggregate([{$project: {'a.b': 1}}, {$sort: {_id: 1}}]).toArray(),
+ coll.find({}, {'a.b': 1}).sort({_id: 1}).toArray());
+}());
diff --git a/jstests/aggregation/bugs/server6779.js b/jstests/aggregation/bugs/server6779.js
index e3b8aaeca08..44f641ea15d 100644
--- a/jstests/aggregation/bugs/server6779.js
+++ b/jstests/aggregation/bugs/server6779.js
@@ -1,17 +1,20 @@
// server 6779: serializing ExpressionCoerceToBool
// This test only fails in debug mode with the bug since that tests round-tripping
-function test(op, val) {
- t = db.server6779;
- t.drop();
+(function() {
+ "use strict";
- t.insert({a: true});
- t.insert({a: false});
+ function test(op, val) {
+ const coll = db.server6779;
+ coll.drop();
+ assert.writeOK(coll.insert({a: true}));
+ assert.writeOK(coll.insert({a: false}));
- obj = {};
- obj[op] = ['$a', val];
- result = t.aggregate({$project: {_id: 0, bool: obj}});
+ const obj = {};
+ obj[op] = ['$a', val];
+ const result = coll.aggregate([{$project: {_id: 0, bool: obj}}, {$sort: {bool: -1}}]);
- assert.eq(result.toArray(), [{bool: true}, {bool: false}]);
-}
-test('$and', true);
-test('$or', false);
+ assert.eq(result.toArray(), [{bool: true}, {bool: false}]);
+ }
+ test('$and', true);
+ test('$or', false);
+}());
diff --git a/jstests/aggregation/bugs/sort_arrays.js b/jstests/aggregation/bugs/sort_arrays.js
index 47c27736b76..9fbb707decb 100644
--- a/jstests/aggregation/bugs/sort_arrays.js
+++ b/jstests/aggregation/bugs/sort_arrays.js
@@ -2,15 +2,16 @@
// array.
(function() {
"use strict";
+
const coll = db.foo;
coll.drop();
assert.writeOK(coll.insert([{_id: 2, a: [2, 3]}, {_id: 3, a: [2, 4]}, {_id: 4, a: [2, 1]}]));
const expectedOrder = [{_id: 4, a: [2, 1]}, {_id: 2, a: [2, 3]}, {_id: 3, a: [2, 4]}];
- assert.eq(coll.aggregate([{$sort: {a: 1}}]).toArray(), expectedOrder);
- assert.eq(coll.find().sort({a: 1}).toArray(), expectedOrder);
+ assert.eq(coll.aggregate([{$sort: {a: 1, _id: 1}}]).toArray(), expectedOrder);
+ assert.eq(coll.find().sort({a: 1, _id: 1}).toArray(), expectedOrder);
assert.commandWorked(coll.ensureIndex({a: 1}));
- assert.eq(coll.aggregate([{$sort: {a: 1}}]).toArray(), expectedOrder);
- assert.eq(coll.find().sort({a: 1}).toArray(), expectedOrder);
+ assert.eq(coll.aggregate([{$sort: {a: 1, _id: 1}}]).toArray(), expectedOrder);
+ assert.eq(coll.find().sort({a: 1, _id: 1}).toArray(), expectedOrder);
}());