summaryrefslogtreecommitdiff
path: root/jstests/aggregation/bugs
diff options
context:
space:
mode:
Diffstat (limited to 'jstests/aggregation/bugs')
-rw-r--r--jstests/aggregation/bugs/cond.js137
-rw-r--r--jstests/aggregation/bugs/cursor_timeout.js135
-rw-r--r--jstests/aggregation/bugs/explain_options_helper.js30
-rw-r--r--jstests/aggregation/bugs/firstlast.js225
-rw-r--r--jstests/aggregation/bugs/groupMissing.js94
-rw-r--r--jstests/aggregation/bugs/lookup_unwind_getmore.js68
-rw-r--r--jstests/aggregation/bugs/lookup_unwind_killcursor.js62
-rw-r--r--jstests/aggregation/bugs/match.js321
-rw-r--r--jstests/aggregation/bugs/match_swap_limit.js22
-rw-r--r--jstests/aggregation/bugs/reverseArray.js38
-rw-r--r--jstests/aggregation/bugs/server10176.js104
-rw-r--r--jstests/aggregation/bugs/server11118.js299
-rw-r--r--jstests/aggregation/bugs/server11675.js441
-rw-r--r--jstests/aggregation/bugs/server12015.js124
-rw-r--r--jstests/aggregation/bugs/server14421.js74
-rw-r--r--jstests/aggregation/bugs/server14670.js24
-rw-r--r--jstests/aggregation/bugs/server14691.js74
-rw-r--r--jstests/aggregation/bugs/server14872.js48
-rw-r--r--jstests/aggregation/bugs/server17224.js32
-rw-r--r--jstests/aggregation/bugs/server17943.js134
-rw-r--r--jstests/aggregation/bugs/server18198.js114
-rw-r--r--jstests/aggregation/bugs/server18222.js72
-rw-r--r--jstests/aggregation/bugs/server18427.js299
-rw-r--r--jstests/aggregation/bugs/server20163.js334
-rw-r--r--jstests/aggregation/bugs/server20168.js59
-rw-r--r--jstests/aggregation/bugs/server20169.js118
-rw-r--r--jstests/aggregation/bugs/server21632.js145
-rw-r--r--jstests/aggregation/bugs/server22093.js52
-rw-r--r--jstests/aggregation/bugs/server22580.js79
-rw-r--r--jstests/aggregation/bugs/server25590.js24
-rw-r--r--jstests/aggregation/bugs/server26462.js40
-rw-r--r--jstests/aggregation/bugs/server37750.js120
-rw-r--r--jstests/aggregation/bugs/server4588.js99
-rw-r--r--jstests/aggregation/bugs/server4589.js126
-rw-r--r--jstests/aggregation/bugs/server4638.js2
-rw-r--r--jstests/aggregation/bugs/server5012.js14
-rw-r--r--jstests/aggregation/bugs/server533.js56
-rw-r--r--jstests/aggregation/bugs/server6074.js148
-rw-r--r--jstests/aggregation/bugs/server6125.js6
-rw-r--r--jstests/aggregation/bugs/server6127.js28
-rw-r--r--jstests/aggregation/bugs/server6147.js70
-rw-r--r--jstests/aggregation/bugs/server6179.js98
-rw-r--r--jstests/aggregation/bugs/server6185.js20
-rw-r--r--jstests/aggregation/bugs/server6530.js48
-rw-r--r--jstests/aggregation/bugs/server6779.js26
-rw-r--r--jstests/aggregation/bugs/server7695_isodates.js469
-rw-r--r--jstests/aggregation/bugs/server7781.js232
-rw-r--r--jstests/aggregation/bugs/server8141.js72
-rw-r--r--jstests/aggregation/bugs/server8164.js280
-rw-r--r--jstests/aggregation/bugs/server8568.js72
-rw-r--r--jstests/aggregation/bugs/server8581.js64
-rw-r--r--jstests/aggregation/bugs/server9444.js90
-rw-r--r--jstests/aggregation/bugs/server9625.js116
-rw-r--r--jstests/aggregation/bugs/skip_limit_overflow.js193
-rw-r--r--jstests/aggregation/bugs/sort_arrays.js20
-rw-r--r--jstests/aggregation/bugs/substr.js4
56 files changed, 3186 insertions, 3109 deletions
diff --git a/jstests/aggregation/bugs/cond.js b/jstests/aggregation/bugs/cond.js
index 313316f4418..84831ca11a7 100644
--- a/jstests/aggregation/bugs/cond.js
+++ b/jstests/aggregation/bugs/cond.js
@@ -1,88 +1,87 @@
// $cond returns the evaluated second argument if the first evaluates to true but the evaluated
// third argument if the first evaluates to false.
(function() {
- "use strict";
- load('jstests/aggregation/extras/utils.js');
+"use strict";
+load('jstests/aggregation/extras/utils.js');
- const coll = db.jstests_aggregation_cond;
- coll.drop();
+const coll = db.jstests_aggregation_cond;
+coll.drop();
- coll.save({});
+coll.save({});
- function assertError(expectedErrorCode, condSpec) {
- assertErrorCode(coll, {$project: {a: {$cond: condSpec}}}, expectedErrorCode);
- }
+function assertError(expectedErrorCode, condSpec) {
+ assertErrorCode(coll, {$project: {a: {$cond: condSpec}}}, expectedErrorCode);
+}
- function assertResult(expectedResult, arg) {
- assert.eq(expectedResult, coll.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]}]);
- assert(coll.drop());
- assert.writeOK(coll.insert({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']);
- assert(coll.drop());
- assert.writeOK(coll.insert({}));
+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.
- 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']}
- ]
+// 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));
+ },
+ {$sort: {meal: 1}}
+ ])
+ .map(doc => doc.meal));
}());
diff --git a/jstests/aggregation/bugs/cursor_timeout.js b/jstests/aggregation/bugs/cursor_timeout.js
index f579fba407d..21260074d26 100644
--- a/jstests/aggregation/bugs/cursor_timeout.js
+++ b/jstests/aggregation/bugs/cursor_timeout.js
@@ -7,83 +7,82 @@
* ]
*/
(function() {
- 'use strict';
+'use strict';
- // Cursor timeout on mongod is handled by a single thread/timer that will sleep for
- // "clientCursorMonitorFrequencySecs" and add the sleep value to each operation's duration when
- // it wakes up, timing out those whose "now() - last accessed since" time exceeds. A cursor
- // timeout of 2 seconds with a monitor frequency of 1 second means an effective timeout period
- // of 1 to 2 seconds.
- const cursorTimeoutMs = 2000;
- const cursorMonitorFrequencySecs = 1;
+// Cursor timeout on mongod is handled by a single thread/timer that will sleep for
+// "clientCursorMonitorFrequencySecs" and add the sleep value to each operation's duration when
+// it wakes up, timing out those whose "now() - last accessed since" time exceeds. A cursor
+// timeout of 2 seconds with a monitor frequency of 1 second means an effective timeout period
+// of 1 to 2 seconds.
+const cursorTimeoutMs = 2000;
+const cursorMonitorFrequencySecs = 1;
- const options = {
- setParameter: {
- internalDocumentSourceCursorBatchSizeBytes: 1,
- // We use the "cursorTimeoutMillis" server parameter to decrease how long it takes for a
- // non-exhausted cursor to time out. We use the "clientCursorMonitorFrequencySecs"
- // server parameter to make the ClientCursorMonitor that cleans up the timed out cursors
- // run more often. The combination of these server parameters reduces the amount of time
- // we need to wait within this test.
- cursorTimeoutMillis: cursorTimeoutMs,
- clientCursorMonitorFrequencySecs: cursorMonitorFrequencySecs,
- }
- };
- const conn = MongoRunner.runMongod(options);
- assert.neq(null, conn, 'mongod was unable to start up with options: ' + tojson(options));
+const options = {
+ setParameter: {
+ internalDocumentSourceCursorBatchSizeBytes: 1,
+ // We use the "cursorTimeoutMillis" server parameter to decrease how long it takes for a
+ // non-exhausted cursor to time out. We use the "clientCursorMonitorFrequencySecs"
+ // server parameter to make the ClientCursorMonitor that cleans up the timed out cursors
+ // run more often. The combination of these server parameters reduces the amount of time
+ // we need to wait within this test.
+ cursorTimeoutMillis: cursorTimeoutMs,
+ clientCursorMonitorFrequencySecs: cursorMonitorFrequencySecs,
+ }
+};
+const conn = MongoRunner.runMongod(options);
+assert.neq(null, conn, 'mongod was unable to start up with options: ' + tojson(options));
- const testDB = conn.getDB('test');
+const testDB = conn.getDB('test');
- // We use a batch size of 2 to ensure that the mongo shell does not exhaust the cursor on its
- // first batch.
- const batchSize = 2;
- const numMatches = 5;
+// We use a batch size of 2 to ensure that the mongo shell does not exhaust the cursor on its
+// first batch.
+const batchSize = 2;
+const numMatches = 5;
- function assertCursorTimesOut(collName, pipeline) {
- const res = assert.commandWorked(testDB.runCommand({
- aggregate: collName,
- pipeline: pipeline,
- cursor: {
- batchSize: batchSize,
- },
- }));
+function assertCursorTimesOut(collName, pipeline) {
+ const res = assert.commandWorked(testDB.runCommand({
+ aggregate: collName,
+ pipeline: pipeline,
+ cursor: {
+ batchSize: batchSize,
+ },
+ }));
- let serverStatus = assert.commandWorked(testDB.serverStatus());
- const expectedNumTimedOutCursors = serverStatus.metrics.cursor.timedOut + 1;
+ let serverStatus = assert.commandWorked(testDB.serverStatus());
+ const expectedNumTimedOutCursors = serverStatus.metrics.cursor.timedOut + 1;
- const cursor = new DBCommandCursor(testDB, res, batchSize);
+ const cursor = new DBCommandCursor(testDB, res, batchSize);
- // Wait until the idle cursor background job has killed the aggregation cursor.
- assert.soon(
- function() {
- serverStatus = assert.commandWorked(testDB.serverStatus());
- return +serverStatus.metrics.cursor.timedOut === expectedNumTimedOutCursors;
- },
- function() {
- return "aggregation cursor failed to time out: " +
- tojson(serverStatus.metrics.cursor);
- });
+ // Wait until the idle cursor background job has killed the aggregation cursor.
+ assert.soon(
+ function() {
+ serverStatus = assert.commandWorked(testDB.serverStatus());
+ return +serverStatus.metrics.cursor.timedOut === expectedNumTimedOutCursors;
+ },
+ function() {
+ return "aggregation cursor failed to time out: " + tojson(serverStatus.metrics.cursor);
+ });
- assert.eq(0, serverStatus.metrics.cursor.open.total, tojson(serverStatus));
+ assert.eq(0, serverStatus.metrics.cursor.open.total, tojson(serverStatus));
- // We attempt to exhaust the aggregation cursor to verify that sending a getMore returns an
- // error due to the cursor being killed.
- let err = assert.throws(function() {
- cursor.itcount();
- });
- assert.eq(ErrorCodes.CursorNotFound, err.code, tojson(err));
- }
+ // We attempt to exhaust the aggregation cursor to verify that sending a getMore returns an
+ // error due to the cursor being killed.
+ let err = assert.throws(function() {
+ cursor.itcount();
+ });
+ assert.eq(ErrorCodes.CursorNotFound, err.code, tojson(err));
+}
- assert.writeOK(testDB.source.insert({local: 1}));
- for (let i = 0; i < numMatches; ++i) {
- assert.writeOK(testDB.dest.insert({foreign: 1}));
- }
+assert.writeOK(testDB.source.insert({local: 1}));
+for (let i = 0; i < numMatches; ++i) {
+ assert.writeOK(testDB.dest.insert({foreign: 1}));
+}
- // Test that a regular aggregation cursor is killed when the timeout is reached.
- assertCursorTimesOut('dest', []);
+// Test that a regular aggregation cursor is killed when the timeout is reached.
+assertCursorTimesOut('dest', []);
- // Test that an aggregation cursor with a $lookup stage is killed when the timeout is reached.
- assertCursorTimesOut('source', [
+// Test that an aggregation cursor with a $lookup stage is killed when the timeout is reached.
+assertCursorTimesOut('source', [
{
$lookup: {
from: 'dest',
@@ -97,9 +96,9 @@
},
]);
- // Test that an aggregation cursor with nested $lookup stages is killed when the timeout is
- // reached.
- assertCursorTimesOut('source', [
+// Test that an aggregation cursor with nested $lookup stages is killed when the timeout is
+// reached.
+assertCursorTimesOut('source', [
{
$lookup: {
from: 'dest',
@@ -126,5 +125,5 @@
},
]);
- MongoRunner.stopMongod(conn);
+MongoRunner.stopMongod(conn);
})();
diff --git a/jstests/aggregation/bugs/explain_options_helper.js b/jstests/aggregation/bugs/explain_options_helper.js
index 17360acab73..0834d56e469 100644
--- a/jstests/aggregation/bugs/explain_options_helper.js
+++ b/jstests/aggregation/bugs/explain_options_helper.js
@@ -2,23 +2,25 @@
// This test was designed to reproduce SERVER-32300".
(function() {
- "use strict";
+"use strict";
- const coll = db.explain_options;
- coll.drop();
+const coll = db.explain_options;
+coll.drop();
- for (let i = 0; i < 10; ++i) {
- assert.writeOK(coll.insert({_id: i}));
- }
+for (let i = 0; i < 10; ++i) {
+ assert.writeOK(coll.insert({_id: i}));
+}
- const collation = {collation: {locale: "zh", backwards: false}};
+const collation = {
+ collation: {locale: "zh", backwards: false}
+};
- const firstResults = coll.aggregate([{$sort: {_id: 1}}], collation).toArray();
- // Issue an explain in order to verify that 'collation' is not modified to include the explain
- // flag.
- assert.commandWorked(coll.explain().aggregate([], collation));
+const firstResults = coll.aggregate([{$sort: {_id: 1}}], collation).toArray();
+// Issue an explain in order to verify that 'collation' is not modified to include the explain
+// flag.
+assert.commandWorked(coll.explain().aggregate([], collation));
- const secondResults = coll.aggregate([{$sort: {_id: 1}}], collation).toArray();
- // Assert that the result didn't change after an explain helper is issued.
- assert.eq(firstResults, secondResults);
+const secondResults = coll.aggregate([{$sort: {_id: 1}}], collation).toArray();
+// Assert that the result didn't change after an explain helper is issued.
+assert.eq(firstResults, secondResults);
}());
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]});
}());
diff --git a/jstests/aggregation/bugs/groupMissing.js b/jstests/aggregation/bugs/groupMissing.js
index c08e70185b1..5f734abbee5 100644
--- a/jstests/aggregation/bugs/groupMissing.js
+++ b/jstests/aggregation/bugs/groupMissing.js
@@ -8,68 +8,68 @@
load('jstests/aggregation/extras/utils.js'); // For resultsEq.
(function() {
- "use strict";
+"use strict";
- var coll = db.groupMissing;
- coll.drop();
+var coll = db.groupMissing;
+coll.drop();
- coll.insert({a: null});
- coll.insert({});
+coll.insert({a: null});
+coll.insert({});
- var res = coll.aggregate({$group: {_id: "$a"}});
- var arr = res.toArray();
- assert.eq(arr.length, 1);
- assert.eq(arr[0]._id, null);
+var res = coll.aggregate({$group: {_id: "$a"}});
+var arr = res.toArray();
+assert.eq(arr.length, 1);
+assert.eq(arr[0]._id, null);
- coll.createIndex({a: 1});
- res = coll.aggregate({$sort: {a: 1}}, {$group: {_id: "$a"}});
- arr = res.toArray();
- assert.eq(arr.length, 1);
- assert.eq(arr[0]._id, null);
+coll.createIndex({a: 1});
+res = coll.aggregate({$sort: {a: 1}}, {$group: {_id: "$a"}});
+arr = res.toArray();
+assert.eq(arr.length, 1);
+assert.eq(arr[0]._id, null);
- coll.drop();
+coll.drop();
- coll.insert({a: null});
- coll.insert({});
+coll.insert({a: null});
+coll.insert({});
- // Bug, see SERVER-21992.
+// Bug, see SERVER-21992.
+res = coll.aggregate({$group: {_id: {a: "$a"}}});
+assert(resultsEq(res.toArray(), [{_id: {a: null}}]));
+
+// Correct behavior after SERVER-21992 is fixed.
+if (0) {
res = coll.aggregate({$group: {_id: {a: "$a"}}});
- assert(resultsEq(res.toArray(), [{_id: {a: null}}]));
+ assert(resultsEq(res.toArray(), [{_id: {a: null}}, {_id: {a: {}}}]));
+}
- // Correct behavior after SERVER-21992 is fixed.
- if (0) {
- res = coll.aggregate({$group: {_id: {a: "$a"}}});
- assert(resultsEq(res.toArray(), [{_id: {a: null}}, {_id: {a: {}}}]));
- }
+// Bug, see SERVER-21992.
+coll.createIndex({a: 1});
+res = coll.aggregate({$group: {_id: {a: "$a"}}});
+assert(resultsEq(res.toArray(), [{_id: {a: null}}]));
- // Bug, see SERVER-21992.
- coll.createIndex({a: 1});
+// Correct behavior after SERVER-21992 is fixed.
+if (0) {
res = coll.aggregate({$group: {_id: {a: "$a"}}});
- assert(resultsEq(res.toArray(), [{_id: {a: null}}]));
+ assert(resultsEq(res.toArray(), [{_id: {a: null}}, {_id: {a: {}}}]));
+}
- // Correct behavior after SERVER-21992 is fixed.
- if (0) {
- res = coll.aggregate({$group: {_id: {a: "$a"}}});
- assert(resultsEq(res.toArray(), [{_id: {a: null}}, {_id: {a: {}}}]));
- }
+coll.drop();
+coll.insert({a: null, b: 1});
+coll.insert({b: 1});
+coll.insert({a: null, b: 1});
- coll.drop();
- 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"}}});
+assert(resultsEq(res.toArray(), [{_id: {b: 1}}, {_id: {a: null, b: 1}}]));
- res = coll.aggregate({$group: {_id: {a: "$a", b: "$b"}}});
- assert(resultsEq(res.toArray(), [{_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}}]));
- // Bug, see SERVER-23229.
+// 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: {a: null, b: 1}}]));
-
- // 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}}]));
- }
+ assert(resultsEq(res.toArray(), [{_id: {b: 1}}, {_id: {a: null, b: 1}}]));
+}
}());
diff --git a/jstests/aggregation/bugs/lookup_unwind_getmore.js b/jstests/aggregation/bugs/lookup_unwind_getmore.js
index 3ba7dbf4007..67b970de820 100644
--- a/jstests/aggregation/bugs/lookup_unwind_getmore.js
+++ b/jstests/aggregation/bugs/lookup_unwind_getmore.js
@@ -8,45 +8,47 @@
* ]
*/
(function() {
- 'use strict';
+'use strict';
- const options = {setParameter: 'internalDocumentSourceCursorBatchSizeBytes=1'};
- const conn = MongoRunner.runMongod(options);
- assert.neq(null, conn, 'mongod was unable to start up with options: ' + tojson(options));
+const options = {
+ setParameter: 'internalDocumentSourceCursorBatchSizeBytes=1'
+};
+const conn = MongoRunner.runMongod(options);
+assert.neq(null, conn, 'mongod was unable to start up with options: ' + tojson(options));
- const testDB = conn.getDB('test');
+const testDB = conn.getDB('test');
- /**
- * Executes an aggregrate with 'options.pipeline' and confirms that 'options.numResults' were
- * returned.
- */
- function runTest(options) {
- // The batchSize must be smaller than the number of documents returned by the $lookup. This
- // ensures that the mongo shell will issue a getMore when unwinding the $lookup results for
- // the same document in the 'source' collection, under a different OperationContext.
- const batchSize = 2;
+/**
+ * Executes an aggregrate with 'options.pipeline' and confirms that 'options.numResults' were
+ * returned.
+ */
+function runTest(options) {
+ // The batchSize must be smaller than the number of documents returned by the $lookup. This
+ // ensures that the mongo shell will issue a getMore when unwinding the $lookup results for
+ // the same document in the 'source' collection, under a different OperationContext.
+ const batchSize = 2;
- testDB.source.drop();
- assert.writeOK(testDB.source.insert({x: 1}));
+ testDB.source.drop();
+ assert.writeOK(testDB.source.insert({x: 1}));
- testDB.dest.drop();
- for (let i = 0; i < 5; ++i) {
- assert.writeOK(testDB.dest.insert({x: 1}));
- }
+ testDB.dest.drop();
+ for (let i = 0; i < 5; ++i) {
+ assert.writeOK(testDB.dest.insert({x: 1}));
+ }
- const res = assert.commandWorked(testDB.runCommand({
- aggregate: 'source',
- pipeline: options.pipeline,
- cursor: {
- batchSize: batchSize,
- },
- }));
+ const res = assert.commandWorked(testDB.runCommand({
+ aggregate: 'source',
+ pipeline: options.pipeline,
+ cursor: {
+ batchSize: batchSize,
+ },
+ }));
- const cursor = new DBCommandCursor(testDB, res, batchSize);
- assert.eq(options.numResults, cursor.itcount());
- }
+ const cursor = new DBCommandCursor(testDB, res, batchSize);
+ assert.eq(options.numResults, cursor.itcount());
+}
- runTest({
+runTest({
pipeline: [
{
$lookup: {
@@ -65,7 +67,7 @@
numResults: 5
});
- runTest({
+runTest({
pipeline: [
{
$lookup: {
@@ -99,5 +101,5 @@
numResults: 25
});
- MongoRunner.stopMongod(conn);
+MongoRunner.stopMongod(conn);
})();
diff --git a/jstests/aggregation/bugs/lookup_unwind_killcursor.js b/jstests/aggregation/bugs/lookup_unwind_killcursor.js
index 45da6350c2f..eab9d05c591 100644
--- a/jstests/aggregation/bugs/lookup_unwind_killcursor.js
+++ b/jstests/aggregation/bugs/lookup_unwind_killcursor.js
@@ -8,43 +8,45 @@
* ]
*/
(function() {
- 'use strict';
+'use strict';
- const options = {setParameter: 'internalDocumentSourceCursorBatchSizeBytes=1'};
- const conn = MongoRunner.runMongod(options);
- assert.neq(null, conn, 'mongod was unable to start up with options: ' + tojson(options));
+const options = {
+ setParameter: 'internalDocumentSourceCursorBatchSizeBytes=1'
+};
+const conn = MongoRunner.runMongod(options);
+assert.neq(null, conn, 'mongod was unable to start up with options: ' + tojson(options));
- const testDB = conn.getDB('test');
+const testDB = conn.getDB('test');
- function runTest(pipeline) {
- // We use a batch size of 2 to ensure that the mongo shell does not exhaust the cursor on
- // its first batch.
- const batchSize = 2;
+function runTest(pipeline) {
+ // We use a batch size of 2 to ensure that the mongo shell does not exhaust the cursor on
+ // its first batch.
+ const batchSize = 2;
- testDB.source.drop();
- assert.writeOK(testDB.source.insert({x: 1}));
+ testDB.source.drop();
+ assert.writeOK(testDB.source.insert({x: 1}));
- testDB.dest.drop();
- for (let i = 0; i < 5; ++i) {
- assert.writeOK(testDB.dest.insert({x: 1}));
- }
+ testDB.dest.drop();
+ for (let i = 0; i < 5; ++i) {
+ assert.writeOK(testDB.dest.insert({x: 1}));
+ }
- const res = assert.commandWorked(testDB.runCommand({
- aggregate: 'source',
- pipeline: pipeline,
- cursor: {
- batchSize: batchSize,
- },
- }));
+ const res = assert.commandWorked(testDB.runCommand({
+ aggregate: 'source',
+ pipeline: pipeline,
+ cursor: {
+ batchSize: batchSize,
+ },
+ }));
- const cursor = new DBCommandCursor(testDB, res, batchSize);
- cursor.close(); // Closing the cursor will issue the "killCursors" command.
+ const cursor = new DBCommandCursor(testDB, res, batchSize);
+ cursor.close(); // Closing the cursor will issue the "killCursors" command.
- const serverStatus = assert.commandWorked(testDB.adminCommand({serverStatus: 1}));
- assert.eq(0, serverStatus.metrics.cursor.open.total, tojson(serverStatus.metrics.cursor));
- }
+ const serverStatus = assert.commandWorked(testDB.adminCommand({serverStatus: 1}));
+ assert.eq(0, serverStatus.metrics.cursor.open.total, tojson(serverStatus.metrics.cursor));
+}
- runTest([
+runTest([
{
$lookup: {
from: 'dest',
@@ -60,7 +62,7 @@
},
]);
- runTest([
+runTest([
{
$lookup: {
from: 'dest',
@@ -91,5 +93,5 @@
},
]);
- MongoRunner.stopMongod(conn);
+MongoRunner.stopMongod(conn);
})();
diff --git a/jstests/aggregation/bugs/match.js b/jstests/aggregation/bugs/match.js
index 8cb4519a861..6a545ed60c1 100644
--- a/jstests/aggregation/bugs/match.js
+++ b/jstests/aggregation/bugs/match.js
@@ -2,166 +2,169 @@
// - Filtering behavior equivalent to a mongo query.
// - $where and geo operators are not allowed
(function() {
- "use strict";
-
- load('jstests/aggregation/extras/utils.js');
-
- const coll = db.jstests_aggregation_match;
- coll.drop();
-
- const identityProjection = {_id: '$_id', a: '$a'};
-
- /** Assert that an aggregation generated the expected error. */
- function assertError(expectedCode, matchSpec) {
- const matchStage = {$match: matchSpec};
- // Check where matching is folded in to DocumentSourceCursor.
- assertErrorCode(coll, [matchStage], expectedCode);
- // Check where matching is not folded in to DocumentSourceCursor.
- assertErrorCode(coll, [{$project: identityProjection}, matchStage], expectedCode);
+"use strict";
+
+load('jstests/aggregation/extras/utils.js');
+
+const coll = db.jstests_aggregation_match;
+coll.drop();
+
+const identityProjection = {
+ _id: '$_id',
+ a: '$a'
+};
+
+/** Assert that an aggregation generated the expected error. */
+function assertError(expectedCode, matchSpec) {
+ const matchStage = {$match: matchSpec};
+ // Check where matching is folded in to DocumentSourceCursor.
+ assertErrorCode(coll, [matchStage], expectedCode);
+ // Check where matching is not folded in to DocumentSourceCursor.
+ assertErrorCode(coll, [{$project: identityProjection}, matchStage], expectedCode);
+}
+
+/** Assert that the contents of two arrays are equal, ignoring element ordering. */
+function assertEqualResultsUnordered(one, two) {
+ let oneStr = one.map(function(x) {
+ return tojson(x);
+ });
+ let twoStr = two.map(function(x) {
+ return tojson(x);
+ });
+ oneStr.sort();
+ twoStr.sort();
+ assert.eq(oneStr, twoStr);
+}
+
+/** Assert that an aggregation result is as expected. */
+function assertResults(expectedResults, matchSpec) {
+ const findResults = coll.find(matchSpec).toArray();
+ if (expectedResults) {
+ assertEqualResultsUnordered(expectedResults, findResults);
}
-
- /** Assert that the contents of two arrays are equal, ignoring element ordering. */
- function assertEqualResultsUnordered(one, two) {
- let oneStr = one.map(function(x) {
- return tojson(x);
- });
- let twoStr = two.map(function(x) {
- return tojson(x);
- });
- oneStr.sort();
- twoStr.sort();
- assert.eq(oneStr, twoStr);
- }
-
- /** Assert that an aggregation result is as expected. */
- function assertResults(expectedResults, matchSpec) {
- const findResults = coll.find(matchSpec).toArray();
- if (expectedResults) {
- assertEqualResultsUnordered(expectedResults, findResults);
- }
- const matchStage = {$match: matchSpec};
- // Check where matching is folded in to DocumentSourceCursor.
- assertEqualResultsUnordered(findResults, coll.aggregate(matchStage).toArray());
- // Check where matching is not folded in to DocumentSourceCursor.
- assertEqualResultsUnordered(
- findResults, coll.aggregate({$project: identityProjection}, matchStage).toArray());
- }
-
- // Invalid matcher syntax.
- assertError(2, {a: {$mod: [0 /* invalid */, 0]}});
-
- // $where not allowed.
- assertError(ErrorCodes.BadValue, {$where: 'true'});
-
- // Geo not allowed.
- assertError(ErrorCodes.BadValue, {$match: {a: {$near: [0, 0]}}});
-
- function checkMatchResults(indexed) {
- // No results.
- coll.remove({});
- assertResults([], {});
-
- assert.writeOK(coll.insert({_id: 0, a: 1}));
- assert.writeOK(coll.insert({_id: 1, a: 2}));
- assert.writeOK(coll.insert({_id: 2, a: 3}));
-
- // Empty query.
- assertResults([{_id: 0, a: 1}, {_id: 1, a: 2}, {_id: 2, a: 3}], {});
-
- // Simple queries.
- assertResults([{_id: 0, a: 1}], {a: 1});
- assertResults([{_id: 1, a: 2}], {a: 2});
- assertResults([{_id: 1, a: 2}, {_id: 2, a: 3}], {a: {$gt: 1}});
- assertResults([{_id: 0, a: 1}, {_id: 1, a: 2}], {a: {$lte: 2}});
- assertResults([{_id: 0, a: 1}, {_id: 2, a: 3}], {a: {$in: [1, 3]}});
-
- // Regular expression.
- coll.remove({});
- assert.writeOK(coll.insert({_id: 0, a: 'x'}));
- assert.writeOK(coll.insert({_id: 1, a: 'yx'}));
- assertResults([{_id: 0, a: 'x'}], {a: /^x/});
- assertResults([{_id: 0, a: 'x'}, {_id: 1, a: 'yx'}], {a: /x/});
-
- // Dotted field.
- coll.remove({});
- assert.writeOK(coll.insert({_id: 0, a: {b: 4}}));
- assert.writeOK(coll.insert({_id: 1, a: 2}));
- assertResults([{_id: 0, a: {b: 4}}], {'a.b': 4});
-
- // Value within an array.
- coll.remove({});
- assert.writeOK(coll.insert({_id: 0, a: [1, 2, 3]}));
- assert.writeOK(coll.insert({_id: 1, a: [2, 2, 3]}));
- assert.writeOK(coll.insert({_id: 2, a: [2, 2, 2]}));
- assertResults([{_id: 0, a: [1, 2, 3]}, {_id: 1, a: [2, 2, 3]}], {a: 3});
-
- // Missing, null, $exists matching.
- coll.remove({});
- assert.writeOK(coll.insert({_id: 0}));
- assert.writeOK(coll.insert({_id: 1, a: null}));
- assert.writeOK(coll.insert({_id: 3, a: 0}));
- assertResults([{_id: 0}, {_id: 1, a: null}], {a: null});
- assertResults(null, {a: {$exists: true}});
- assertResults(null, {a: {$exists: false}});
-
- // $elemMatch
- coll.remove({});
- assert.writeOK(coll.insert({_id: 0, a: [1, 2]}));
- assert.writeOK(coll.insert({_id: 1, a: [1, 2, 3]}));
- assertResults([{_id: 1, a: [1, 2, 3]}], {a: {$elemMatch: {$gt: 1, $mod: [2, 1]}}});
-
- coll.remove({});
- assert.writeOK(coll.insert({_id: 0, a: [{b: 1}, {c: 2}]}));
- assert.writeOK(coll.insert({_id: 1, a: [{b: 1, c: 2}]}));
- assertResults([{_id: 1, a: [{b: 1, c: 2}]}], {a: {$elemMatch: {b: 1, c: 2}}});
-
- // $size
- coll.remove({});
- assert.writeOK(coll.insert({}));
- assert.writeOK(coll.insert({a: null}));
- assert.writeOK(coll.insert({a: []}));
- assert.writeOK(coll.insert({a: [1]}));
- assert.writeOK(coll.insert({a: [1, 2]}));
- assertResults(null, {a: {$size: 0}});
- assertResults(null, {a: {$size: 1}});
- assertResults(null, {a: {$size: 2}});
-
- // $type
- coll.remove({});
- assert.writeOK(coll.insert({}));
- assert.writeOK(coll.insert({a: null}));
- assert.writeOK(coll.insert({a: NumberInt(1)}));
- assert.writeOK(coll.insert({a: NumberLong(2)}));
- assert.writeOK(coll.insert({a: 66.6}));
- assert.writeOK(coll.insert({a: 'abc'}));
- assert.writeOK(coll.insert({a: /xyz/}));
- assert.writeOK(coll.insert({a: {q: 1}}));
- assert.writeOK(coll.insert({a: true}));
- assert.writeOK(coll.insert({a: new Date()}));
- assert.writeOK(coll.insert({a: new ObjectId()}));
- for (let type = 1; type <= 18; ++type) {
- assertResults(null, {a: {$type: type}});
- }
-
- coll.remove({});
- assert.writeOK(coll.insert({_id: 0, a: 1}));
- assert.writeOK(coll.insert({_id: 1, a: 2}));
- assert.writeOK(coll.insert({_id: 2, a: 3}));
-
- // $and
- assertResults([{_id: 1, a: 2}], {$and: [{a: 2}, {_id: 1}]});
- assertResults([], {$and: [{a: 1}, {_id: 1}]});
- assertResults([{_id: 1, a: 2}, {_id: 2, a: 3}],
- {$and: [{$or: [{_id: 1}, {a: 3}]}, {$or: [{_id: 2}, {a: 2}]}]});
-
- // $or
- assertResults([{_id: 0, a: 1}, {_id: 2, a: 3}], {$or: [{_id: 0}, {a: 3}]});
+ const matchStage = {$match: matchSpec};
+ // Check where matching is folded in to DocumentSourceCursor.
+ assertEqualResultsUnordered(findResults, coll.aggregate(matchStage).toArray());
+ // Check where matching is not folded in to DocumentSourceCursor.
+ assertEqualResultsUnordered(
+ findResults, coll.aggregate({$project: identityProjection}, matchStage).toArray());
+}
+
+// Invalid matcher syntax.
+assertError(2, {a: {$mod: [0 /* invalid */, 0]}});
+
+// $where not allowed.
+assertError(ErrorCodes.BadValue, {$where: 'true'});
+
+// Geo not allowed.
+assertError(ErrorCodes.BadValue, {$match: {a: {$near: [0, 0]}}});
+
+function checkMatchResults(indexed) {
+ // No results.
+ coll.remove({});
+ assertResults([], {});
+
+ assert.writeOK(coll.insert({_id: 0, a: 1}));
+ assert.writeOK(coll.insert({_id: 1, a: 2}));
+ assert.writeOK(coll.insert({_id: 2, a: 3}));
+
+ // Empty query.
+ assertResults([{_id: 0, a: 1}, {_id: 1, a: 2}, {_id: 2, a: 3}], {});
+
+ // Simple queries.
+ assertResults([{_id: 0, a: 1}], {a: 1});
+ assertResults([{_id: 1, a: 2}], {a: 2});
+ assertResults([{_id: 1, a: 2}, {_id: 2, a: 3}], {a: {$gt: 1}});
+ assertResults([{_id: 0, a: 1}, {_id: 1, a: 2}], {a: {$lte: 2}});
+ assertResults([{_id: 0, a: 1}, {_id: 2, a: 3}], {a: {$in: [1, 3]}});
+
+ // Regular expression.
+ coll.remove({});
+ assert.writeOK(coll.insert({_id: 0, a: 'x'}));
+ assert.writeOK(coll.insert({_id: 1, a: 'yx'}));
+ assertResults([{_id: 0, a: 'x'}], {a: /^x/});
+ assertResults([{_id: 0, a: 'x'}, {_id: 1, a: 'yx'}], {a: /x/});
+
+ // Dotted field.
+ coll.remove({});
+ assert.writeOK(coll.insert({_id: 0, a: {b: 4}}));
+ assert.writeOK(coll.insert({_id: 1, a: 2}));
+ assertResults([{_id: 0, a: {b: 4}}], {'a.b': 4});
+
+ // Value within an array.
+ coll.remove({});
+ assert.writeOK(coll.insert({_id: 0, a: [1, 2, 3]}));
+ assert.writeOK(coll.insert({_id: 1, a: [2, 2, 3]}));
+ assert.writeOK(coll.insert({_id: 2, a: [2, 2, 2]}));
+ assertResults([{_id: 0, a: [1, 2, 3]}, {_id: 1, a: [2, 2, 3]}], {a: 3});
+
+ // Missing, null, $exists matching.
+ coll.remove({});
+ assert.writeOK(coll.insert({_id: 0}));
+ assert.writeOK(coll.insert({_id: 1, a: null}));
+ assert.writeOK(coll.insert({_id: 3, a: 0}));
+ assertResults([{_id: 0}, {_id: 1, a: null}], {a: null});
+ assertResults(null, {a: {$exists: true}});
+ assertResults(null, {a: {$exists: false}});
+
+ // $elemMatch
+ coll.remove({});
+ assert.writeOK(coll.insert({_id: 0, a: [1, 2]}));
+ assert.writeOK(coll.insert({_id: 1, a: [1, 2, 3]}));
+ assertResults([{_id: 1, a: [1, 2, 3]}], {a: {$elemMatch: {$gt: 1, $mod: [2, 1]}}});
+
+ coll.remove({});
+ assert.writeOK(coll.insert({_id: 0, a: [{b: 1}, {c: 2}]}));
+ assert.writeOK(coll.insert({_id: 1, a: [{b: 1, c: 2}]}));
+ assertResults([{_id: 1, a: [{b: 1, c: 2}]}], {a: {$elemMatch: {b: 1, c: 2}}});
+
+ // $size
+ coll.remove({});
+ assert.writeOK(coll.insert({}));
+ assert.writeOK(coll.insert({a: null}));
+ assert.writeOK(coll.insert({a: []}));
+ assert.writeOK(coll.insert({a: [1]}));
+ assert.writeOK(coll.insert({a: [1, 2]}));
+ assertResults(null, {a: {$size: 0}});
+ assertResults(null, {a: {$size: 1}});
+ assertResults(null, {a: {$size: 2}});
+
+ // $type
+ coll.remove({});
+ assert.writeOK(coll.insert({}));
+ assert.writeOK(coll.insert({a: null}));
+ assert.writeOK(coll.insert({a: NumberInt(1)}));
+ assert.writeOK(coll.insert({a: NumberLong(2)}));
+ assert.writeOK(coll.insert({a: 66.6}));
+ assert.writeOK(coll.insert({a: 'abc'}));
+ assert.writeOK(coll.insert({a: /xyz/}));
+ assert.writeOK(coll.insert({a: {q: 1}}));
+ assert.writeOK(coll.insert({a: true}));
+ assert.writeOK(coll.insert({a: new Date()}));
+ assert.writeOK(coll.insert({a: new ObjectId()}));
+ for (let type = 1; type <= 18; ++type) {
+ assertResults(null, {a: {$type: type}});
}
- checkMatchResults(false);
- coll.createIndex({a: 1});
- checkMatchResults(true);
- coll.createIndex({'a.b': 1});
- coll.createIndex({'a.c': 1});
- checkMatchResults(true);
+ coll.remove({});
+ assert.writeOK(coll.insert({_id: 0, a: 1}));
+ assert.writeOK(coll.insert({_id: 1, a: 2}));
+ assert.writeOK(coll.insert({_id: 2, a: 3}));
+
+ // $and
+ assertResults([{_id: 1, a: 2}], {$and: [{a: 2}, {_id: 1}]});
+ assertResults([], {$and: [{a: 1}, {_id: 1}]});
+ assertResults([{_id: 1, a: 2}, {_id: 2, a: 3}],
+ {$and: [{$or: [{_id: 1}, {a: 3}]}, {$or: [{_id: 2}, {a: 2}]}]});
+
+ // $or
+ assertResults([{_id: 0, a: 1}, {_id: 2, a: 3}], {$or: [{_id: 0}, {a: 3}]});
+}
+
+checkMatchResults(false);
+coll.createIndex({a: 1});
+checkMatchResults(true);
+coll.createIndex({'a.b': 1});
+coll.createIndex({'a.c': 1});
+checkMatchResults(true);
})();
diff --git a/jstests/aggregation/bugs/match_swap_limit.js b/jstests/aggregation/bugs/match_swap_limit.js
index 3de26d6f4b5..7dabc7130ca 100644
--- a/jstests/aggregation/bugs/match_swap_limit.js
+++ b/jstests/aggregation/bugs/match_swap_limit.js
@@ -2,19 +2,19 @@
* Ensure that $match is always applied after $limit.
*/
(function() {
- "use strict";
+"use strict";
- let coll = db.jstests_match_swap_limit;
- coll.drop();
+let coll = db.jstests_match_swap_limit;
+coll.drop();
- assert.writeOK(coll.insert({_id: 0, x: 1, y: 3}));
- assert.writeOK(coll.insert({_id: 1, x: 2, y: 2}));
- assert.writeOK(coll.insert({_id: 2, x: 3, y: 1}));
+assert.writeOK(coll.insert({_id: 0, x: 1, y: 3}));
+assert.writeOK(coll.insert({_id: 1, x: 2, y: 2}));
+assert.writeOK(coll.insert({_id: 2, x: 3, y: 1}));
- assert.eq([{_id: 1, x: 2, y: 2}],
- coll.aggregate([{$sort: {x: -1}}, {$limit: 2}, {$match: {y: {$gte: 2}}}]).toArray());
+assert.eq([{_id: 1, x: 2, y: 2}],
+ coll.aggregate([{$sort: {x: -1}}, {$limit: 2}, {$match: {y: {$gte: 2}}}]).toArray());
- assert.writeOK(coll.createIndex({x: 1}));
- assert.eq([{_id: 1, x: 2, y: 2}],
- coll.aggregate([{$sort: {x: -1}}, {$limit: 2}, {$match: {y: {$gte: 2}}}]).toArray());
+assert.writeOK(coll.createIndex({x: 1}));
+assert.eq([{_id: 1, x: 2, y: 2}],
+ coll.aggregate([{$sort: {x: -1}}, {$limit: 2}, {$match: {y: {$gte: 2}}}]).toArray());
}());
diff --git a/jstests/aggregation/bugs/reverseArray.js b/jstests/aggregation/bugs/reverseArray.js
index 0fa4010654b..cf80c040171 100644
--- a/jstests/aggregation/bugs/reverseArray.js
+++ b/jstests/aggregation/bugs/reverseArray.js
@@ -4,29 +4,29 @@
load("jstests/aggregation/extras/utils.js"); // For assertErrorCode.
(function() {
- "use strict";
+"use strict";
- var coll = db.reverseArray;
- coll.drop();
+var coll = db.reverseArray;
+coll.drop();
- // We need a document to flow through the pipeline, even though we don't care what fields it
- // has.
- coll.insert({});
+// We need a document to flow through the pipeline, even though we don't care what fields it
+// has.
+coll.insert({});
- assertErrorCode(coll, [{$project: {reversed: {$reverseArray: 1}}}], 34435);
+assertErrorCode(coll, [{$project: {reversed: {$reverseArray: 1}}}], 34435);
- var res = coll.aggregate([{$project: {reversed: {$reverseArray: {$literal: [1, 2]}}}}]);
- var output = res.toArray();
- assert.eq(1, output.length);
- assert.eq(output[0].reversed, [2, 1]);
+var res = coll.aggregate([{$project: {reversed: {$reverseArray: {$literal: [1, 2]}}}}]);
+var output = res.toArray();
+assert.eq(1, output.length);
+assert.eq(output[0].reversed, [2, 1]);
- var res = coll.aggregate([{$project: {reversed: {$reverseArray: {$literal: [[1, 2]]}}}}]);
- var output = res.toArray();
- assert.eq(1, output.length);
- assert.eq(output[0].reversed, [[1, 2]]);
+var res = coll.aggregate([{$project: {reversed: {$reverseArray: {$literal: [[1, 2]]}}}}]);
+var output = res.toArray();
+assert.eq(1, output.length);
+assert.eq(output[0].reversed, [[1, 2]]);
- var res = coll.aggregate([{$project: {reversed: {$reverseArray: "$notAField"}}}]);
- var output = res.toArray();
- assert.eq(1, output.length);
- assert.eq(output[0].reversed, null);
+var res = coll.aggregate([{$project: {reversed: {$reverseArray: "$notAField"}}}]);
+var output = res.toArray();
+assert.eq(1, output.length);
+assert.eq(output[0].reversed, null);
}());
diff --git a/jstests/aggregation/bugs/server10176.js b/jstests/aggregation/bugs/server10176.js
index 988beb24f13..9283c819342 100644
--- a/jstests/aggregation/bugs/server10176.js
+++ b/jstests/aggregation/bugs/server10176.js
@@ -4,61 +4,61 @@
load('jstests/aggregation/extras/utils.js');
(function() {
- var coll = db.abs_expr;
- coll.drop();
+var coll = db.abs_expr;
+coll.drop();
- // valid types (numeric and null)
- assert.writeOK(coll.insert({_id: 0, a: 5}));
- assert.writeOK(coll.insert({_id: 1, a: -5}));
- assert.writeOK(coll.insert({_id: 2, a: 5.5}));
- assert.writeOK(coll.insert({_id: 3, a: -5.5}));
- assert.writeOK(coll.insert({_id: 4, a: NumberInt("5")}));
- assert.writeOK(coll.insert({_id: 5, a: NumberInt("-5")}));
- assert.writeOK(coll.insert({_id: 6, a: NumberLong("5")}));
- assert.writeOK(coll.insert({_id: 7, a: NumberLong("-5")}));
- assert.writeOK(coll.insert({_id: 8, a: 0.0}));
- assert.writeOK(coll.insert({_id: 9, a: -0.0}));
- assert.writeOK(coll.insert({_id: 10, a: NumberInt("0")}));
- // INT_MIN is -(2 ^ 31)
- assert.writeOK(coll.insert({_id: 11, a: NumberInt(-Math.pow(2, 31))}));
- assert.writeOK(coll.insert({_id: 12, a: -Math.pow(2, 31)}));
- // 1152921504606846977 is 2^60 + 1, an integer that can't be represented precisely as a double
- assert.writeOK(coll.insert({_id: 13, a: NumberLong("1152921504606846977")}));
- assert.writeOK(coll.insert({_id: 14, a: NumberLong("-1152921504606846977")}));
- assert.writeOK(coll.insert({_id: 15, a: null}));
- assert.writeOK(coll.insert({_id: 16, a: undefined}));
- assert.writeOK(coll.insert({_id: 17, a: NaN}));
- assert.writeOK(coll.insert({_id: 18}));
+// valid types (numeric and null)
+assert.writeOK(coll.insert({_id: 0, a: 5}));
+assert.writeOK(coll.insert({_id: 1, a: -5}));
+assert.writeOK(coll.insert({_id: 2, a: 5.5}));
+assert.writeOK(coll.insert({_id: 3, a: -5.5}));
+assert.writeOK(coll.insert({_id: 4, a: NumberInt("5")}));
+assert.writeOK(coll.insert({_id: 5, a: NumberInt("-5")}));
+assert.writeOK(coll.insert({_id: 6, a: NumberLong("5")}));
+assert.writeOK(coll.insert({_id: 7, a: NumberLong("-5")}));
+assert.writeOK(coll.insert({_id: 8, a: 0.0}));
+assert.writeOK(coll.insert({_id: 9, a: -0.0}));
+assert.writeOK(coll.insert({_id: 10, a: NumberInt("0")}));
+// INT_MIN is -(2 ^ 31)
+assert.writeOK(coll.insert({_id: 11, a: NumberInt(-Math.pow(2, 31))}));
+assert.writeOK(coll.insert({_id: 12, a: -Math.pow(2, 31)}));
+// 1152921504606846977 is 2^60 + 1, an integer that can't be represented precisely as a double
+assert.writeOK(coll.insert({_id: 13, a: NumberLong("1152921504606846977")}));
+assert.writeOK(coll.insert({_id: 14, a: NumberLong("-1152921504606846977")}));
+assert.writeOK(coll.insert({_id: 15, a: null}));
+assert.writeOK(coll.insert({_id: 16, a: undefined}));
+assert.writeOK(coll.insert({_id: 17, a: NaN}));
+assert.writeOK(coll.insert({_id: 18}));
- // valid use of $abs: numbers become positive, null/undefined/nonexistent become null
+// valid use of $abs: numbers become positive, null/undefined/nonexistent become null
- var results = coll.aggregate([{$project: {a: {$abs: "$a"}}}, {$sort: {_id: 1}}]).toArray();
- assert.eq(results, [
- {_id: 0, a: 5},
- {_id: 1, a: 5},
- {_id: 2, a: 5.5},
- {_id: 3, a: 5.5},
- {_id: 4, a: 5},
- {_id: 5, a: 5},
- {_id: 6, a: NumberLong("5")},
- {_id: 7, a: NumberLong("5")},
- {_id: 8, a: 0},
- {_id: 9, a: 0},
- {_id: 10, a: 0},
- {_id: 11, a: NumberLong(Math.pow(2, 31))},
- {_id: 12, a: Math.pow(2, 31)},
- {_id: 13, a: NumberLong("1152921504606846977")},
- {_id: 14, a: NumberLong("1152921504606846977")},
- {_id: 15, a: null},
- {_id: 16, a: null},
- {_id: 17, a: NaN},
- {_id: 18, a: null},
- ]);
- // Invalid
+var results = coll.aggregate([{$project: {a: {$abs: "$a"}}}, {$sort: {_id: 1}}]).toArray();
+assert.eq(results, [
+ {_id: 0, a: 5},
+ {_id: 1, a: 5},
+ {_id: 2, a: 5.5},
+ {_id: 3, a: 5.5},
+ {_id: 4, a: 5},
+ {_id: 5, a: 5},
+ {_id: 6, a: NumberLong("5")},
+ {_id: 7, a: NumberLong("5")},
+ {_id: 8, a: 0},
+ {_id: 9, a: 0},
+ {_id: 10, a: 0},
+ {_id: 11, a: NumberLong(Math.pow(2, 31))},
+ {_id: 12, a: Math.pow(2, 31)},
+ {_id: 13, a: NumberLong("1152921504606846977")},
+ {_id: 14, a: NumberLong("1152921504606846977")},
+ {_id: 15, a: null},
+ {_id: 16, a: null},
+ {_id: 17, a: NaN},
+ {_id: 18, a: null},
+]);
+// Invalid
- // using $abs on string
- assertErrorCode(coll, [{$project: {a: {$abs: "string"}}}], 28765);
+// using $abs on string
+assertErrorCode(coll, [{$project: {a: {$abs: "string"}}}], 28765);
- // using $abs on LLONG_MIN (-2 ^ 63)
- assertErrorCode(coll, [{$project: {a: {$abs: NumberLong("-9223372036854775808")}}}], 28680);
+// using $abs on LLONG_MIN (-2 ^ 63)
+assertErrorCode(coll, [{$project: {a: {$abs: NumberLong("-9223372036854775808")}}}], 28680);
}());
diff --git a/jstests/aggregation/bugs/server11118.js b/jstests/aggregation/bugs/server11118.js
index 27b3fa7597e..46e79c3a7cc 100644
--- a/jstests/aggregation/bugs/server11118.js
+++ b/jstests/aggregation/bugs/server11118.js
@@ -1,154 +1,153 @@
// SERVER-11118 Tests for $dateToString
(function() {
- "use strict";
-
- load('jstests/aggregation/extras/utils.js');
-
- const coll = db.server11118;
-
- // Used to verify expected output format
- function testFormat(date, formatStr, expectedStr) {
- coll.drop();
- assert.writeOK(coll.insert({date: date}));
-
- const res =
- coll.aggregate([{
- $project:
- {_id: 0, formatted: {$dateToString: {format: formatStr, date: "$date"}}}
- }])
- .toArray();
-
- assert.eq(res[0].formatted, expectedStr);
- }
-
- // Used to verify that server recognizes bad formats
- function testFormatError(formatObj, errCode) {
- coll.drop();
- assert.writeOK(coll.insert({date: ISODate()}));
-
- assertErrorCode(coll, {$project: {_id: 0, formatted: {$dateToString: formatObj}}}, errCode);
- }
-
- // Used to verify that only date values are accepted for date parameter
- function testDateValueError(dateVal, errCode) {
- coll.drop();
- assert.writeOK(coll.insert({date: dateVal}));
-
- assertErrorCode(
- coll, {$project: {formatted: {$dateToString: {format: "%Y", date: "$date"}}}}, errCode);
- }
-
- const now = ISODate();
-
- // Use all modifiers we can test with js provided function
- testFormat(now, "%%-%Y-%m-%d-%H-%M-%S-%L", [
- "%",
- now.getUTCFullYear().zeroPad(4),
- (now.getUTCMonth() + 1).zeroPad(2),
- now.getUTCDate().zeroPad(2),
- now.getUTCHours().zeroPad(2),
- now.getUTCMinutes().zeroPad(2),
- now.getUTCSeconds().zeroPad(2),
- now.getUTCMilliseconds().zeroPad(3)
- ].join("-"));
-
- // Padding tests
- const padme = ISODate("2001-02-03T04:05:06.007Z");
-
- testFormat(padme, "%%", "%");
- testFormat(padme, "%Y", padme.getUTCFullYear().zeroPad(4));
- testFormat(padme, "%m", (padme.getUTCMonth() + 1).zeroPad(2));
- testFormat(padme, "%d", padme.getUTCDate().zeroPad(2));
- testFormat(padme, "%H", padme.getUTCHours().zeroPad(2));
- testFormat(padme, "%M", padme.getUTCMinutes().zeroPad(2));
- testFormat(padme, "%S", padme.getUTCSeconds().zeroPad(2));
- testFormat(padme, "%L", padme.getUTCMilliseconds().zeroPad(3));
-
- // no space and multiple characters between modifiers
- testFormat(now, "%d%d***%d***%d**%d*%d", [
- now.getUTCDate().zeroPad(2),
- now.getUTCDate().zeroPad(2),
- "***",
- now.getUTCDate().zeroPad(2),
- "***",
- now.getUTCDate().zeroPad(2),
- "**",
- now.getUTCDate().zeroPad(2),
- "*",
- now.getUTCDate().zeroPad(2)
- ].join(""));
-
- // JS doesn't have equivalents of these format specifiers
- testFormat(ISODate('1999-01-02 03:04:05.006Z'), "%U-%w-%j", "00-7-002");
-
- // Missing date
- testFormatError({format: "%Y"}, 18628);
-
- // Extra field
- testFormatError({format: "%Y", date: "$date", extra: "whyamIhere"}, 18534);
-
- // Not an object
- testFormatError(["%Y", "$date"], 18629);
-
- // Use invalid modifier at middle of string
- testFormatError({format: "%Y-%q", date: "$date"}, 18536);
-
- // Odd number of percent signs at end
- testFormatError({format: "%U-%w-%j-%%%", date: "$date"}, 18535);
-
- // Odd number of percent signs at middle
- // will get interpreted as an invalid modifier since it will try to use '%A'
- testFormatError({format: "AAAAA%%%AAAAAA", date: "$date"}, 18536);
-
- // Format parameter not a string
- testFormatError({format: {iamalion: "roar"}, date: "$date"}, 18533);
-
- ///
- /// Additional Tests
- ///
-
- // Test document
- const date = ISODate("1999-08-29");
-
- testFormat(date, "%%d", "%d");
-
- // A very long string of "%"s
- const longstr = Array(1000).join("%%");
- const halfstr = Array(1000).join("%");
- testFormat(date, longstr, halfstr);
-
- // Dates as null (should return a null)
- testFormat(null, "%Y", null);
-
- ///
- /// Using non-date fields as date parameter *should fail*
- ///
-
- // Array
- testDateValueError([], 16006);
- testDateValueError([1, 2, 3], 16006);
-
- // Sub-object
- testDateValueError({}, 16006);
- testDateValueError({a: 1}, 16006);
-
- // String
- testDateValueError("blahblahblah", 16006);
-
- // Integer
- testDateValueError(1234, 16006);
-
- ///
- /// Using non-string fields as format strings
- ///
-
- // Array
- testFormatError({format: [], date: "$date"}, 18533);
- testFormatError({format: [1, 2, 3], date: "$date"}, 18533);
-
- // Integer
- testFormatError({format: 1, date: "$date"}, 18533);
+"use strict";
+
+load('jstests/aggregation/extras/utils.js');
+
+const coll = db.server11118;
+
+// Used to verify expected output format
+function testFormat(date, formatStr, expectedStr) {
+ coll.drop();
+ assert.writeOK(coll.insert({date: date}));
+
+ const res =
+ coll.aggregate([
+ {$project: {_id: 0, formatted: {$dateToString: {format: formatStr, date: "$date"}}}}
+ ])
+ .toArray();
+
+ assert.eq(res[0].formatted, expectedStr);
+}
+
+// Used to verify that server recognizes bad formats
+function testFormatError(formatObj, errCode) {
+ coll.drop();
+ assert.writeOK(coll.insert({date: ISODate()}));
+
+ assertErrorCode(coll, {$project: {_id: 0, formatted: {$dateToString: formatObj}}}, errCode);
+}
+
+// Used to verify that only date values are accepted for date parameter
+function testDateValueError(dateVal, errCode) {
+ coll.drop();
+ assert.writeOK(coll.insert({date: dateVal}));
+
+ assertErrorCode(
+ coll, {$project: {formatted: {$dateToString: {format: "%Y", date: "$date"}}}}, errCode);
+}
+
+const now = ISODate();
+
+// Use all modifiers we can test with js provided function
+testFormat(now, "%%-%Y-%m-%d-%H-%M-%S-%L", [
+ "%",
+ now.getUTCFullYear().zeroPad(4),
+ (now.getUTCMonth() + 1).zeroPad(2),
+ now.getUTCDate().zeroPad(2),
+ now.getUTCHours().zeroPad(2),
+ now.getUTCMinutes().zeroPad(2),
+ now.getUTCSeconds().zeroPad(2),
+ now.getUTCMilliseconds().zeroPad(3)
+].join("-"));
+
+// Padding tests
+const padme = ISODate("2001-02-03T04:05:06.007Z");
+
+testFormat(padme, "%%", "%");
+testFormat(padme, "%Y", padme.getUTCFullYear().zeroPad(4));
+testFormat(padme, "%m", (padme.getUTCMonth() + 1).zeroPad(2));
+testFormat(padme, "%d", padme.getUTCDate().zeroPad(2));
+testFormat(padme, "%H", padme.getUTCHours().zeroPad(2));
+testFormat(padme, "%M", padme.getUTCMinutes().zeroPad(2));
+testFormat(padme, "%S", padme.getUTCSeconds().zeroPad(2));
+testFormat(padme, "%L", padme.getUTCMilliseconds().zeroPad(3));
+
+// no space and multiple characters between modifiers
+testFormat(now, "%d%d***%d***%d**%d*%d", [
+ now.getUTCDate().zeroPad(2),
+ now.getUTCDate().zeroPad(2),
+ "***",
+ now.getUTCDate().zeroPad(2),
+ "***",
+ now.getUTCDate().zeroPad(2),
+ "**",
+ now.getUTCDate().zeroPad(2),
+ "*",
+ now.getUTCDate().zeroPad(2)
+].join(""));
+
+// JS doesn't have equivalents of these format specifiers
+testFormat(ISODate('1999-01-02 03:04:05.006Z'), "%U-%w-%j", "00-7-002");
+
+// Missing date
+testFormatError({format: "%Y"}, 18628);
+
+// Extra field
+testFormatError({format: "%Y", date: "$date", extra: "whyamIhere"}, 18534);
+
+// Not an object
+testFormatError(["%Y", "$date"], 18629);
+
+// Use invalid modifier at middle of string
+testFormatError({format: "%Y-%q", date: "$date"}, 18536);
+
+// Odd number of percent signs at end
+testFormatError({format: "%U-%w-%j-%%%", date: "$date"}, 18535);
+
+// Odd number of percent signs at middle
+// will get interpreted as an invalid modifier since it will try to use '%A'
+testFormatError({format: "AAAAA%%%AAAAAA", date: "$date"}, 18536);
+
+// Format parameter not a string
+testFormatError({format: {iamalion: "roar"}, date: "$date"}, 18533);
+
+///
+/// Additional Tests
+///
+
+// Test document
+const date = ISODate("1999-08-29");
+
+testFormat(date, "%%d", "%d");
+
+// A very long string of "%"s
+const longstr = Array(1000).join("%%");
+const halfstr = Array(1000).join("%");
+testFormat(date, longstr, halfstr);
+
+// Dates as null (should return a null)
+testFormat(null, "%Y", null);
+
+///
+/// Using non-date fields as date parameter *should fail*
+///
+
+// Array
+testDateValueError([], 16006);
+testDateValueError([1, 2, 3], 16006);
+
+// Sub-object
+testDateValueError({}, 16006);
+testDateValueError({a: 1}, 16006);
+
+// String
+testDateValueError("blahblahblah", 16006);
+
+// Integer
+testDateValueError(1234, 16006);
+
+///
+/// Using non-string fields as format strings
+///
+
+// Array
+testFormatError({format: [], date: "$date"}, 18533);
+testFormatError({format: [1, 2, 3], date: "$date"}, 18533);
+
+// Integer
+testFormatError({format: 1, date: "$date"}, 18533);
- // Date
- testFormatError({format: ISODate(), date: "$date"}, 18533);
+// Date
+testFormatError({format: ISODate(), date: "$date"}, 18533);
})();
diff --git a/jstests/aggregation/bugs/server11675.js b/jstests/aggregation/bugs/server11675.js
index 759b4393b30..2d02a1ff53e 100644
--- a/jstests/aggregation/bugs/server11675.js
+++ b/jstests/aggregation/bugs/server11675.js
@@ -1,227 +1,224 @@
// SERVER-11675 Text search integration with aggregation
(function() {
- load('jstests/aggregation/extras/utils.js'); // For 'assertErrorCode'.
- load('jstests/libs/fixture_helpers.js'); // For 'FixtureHelpers'
-
- const coll = db.server11675;
- coll.drop();
-
- 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}));
-
- assert.commandWorked(coll.createIndex({text: "text"}));
-
- // query should have subfields query, project, sort, skip and limit. All but query are optional.
- const assertSameAsFind = function(query) {
- let cursor = coll.find(query.query);
- const pipeline = [{$match: query.query}];
-
- if ('project' in query) {
- cursor = coll.find(query.query, query.project); // no way to add to constructed cursor
- pipeline.push({$project: query.project});
- }
-
- if ('sort' in query) {
- cursor = cursor.sort(query.sort);
- pipeline.push({$sort: query.sort});
- }
-
- if ('skip' in query) {
- cursor = cursor.skip(query.skip);
- pipeline.push({$skip: query.skip});
- }
-
- if ('limit' in query) {
- cursor = cursor.limit(query.limit);
- pipeline.push({$limit: query.limit});
- }
-
- 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
- // client side, so that the results still count as equal.
- if (!query.hasOwnProperty("sort")) {
- findRes.sort(function(a, b) {
- return a._id - b._id;
- });
- aggRes.sort(function(a, b) {
- return a._id - b._id;
- });
- }
-
- assert.docEq(aggRes, findRes);
- };
-
- assertSameAsFind({query: {}}); // sanity check
- assertSameAsFind({query: {$text: {$search: "apple"}}});
- assertSameAsFind({query: {_id: 1, $text: {$search: "apple"}}});
- assertSameAsFind(
- {query: {$text: {$search: "apple"}}, project: {_id: 1, score: {$meta: "textScore"}}});
- assertSameAsFind({
- query: {$text: {$search: "apple banana"}},
- project: {_id: 1, score: {$meta: "textScore"}}
- });
- assertSameAsFind({
- query: {$text: {$search: "apple banana"}},
- project: {_id: 1, score: {$meta: "textScore"}},
- sort: {score: {$meta: "textScore"}}
- });
- assertSameAsFind({
- query: {$text: {$search: "apple banana"}},
- project: {_id: 1, score: {$meta: "textScore"}},
- sort: {score: {$meta: "textScore"}},
- limit: 1
- });
- assertSameAsFind({
- query: {$text: {$search: "apple banana"}},
- project: {_id: 1, score: {$meta: "textScore"}},
- sort: {score: {$meta: "textScore"}},
- skip: 1
- });
- assertSameAsFind({
- query: {$text: {$search: "apple banana"}},
- project: {_id: 1, score: {$meta: "textScore"}},
- sort: {score: {$meta: "textScore"}},
- skip: 1,
- limit: 1
- });
-
- // $meta sort specification should be rejected if it has additional keys.
- assert.throws(function() {
- 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() {
- 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() {
- 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() {
- 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 = 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;
- });
- 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
- 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
- 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
- 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);
- let score = res[0].scoreOnMerger; // save for later tests
-
- // Make sure metadata crosses shard -> merger boundary even if not used on shard
- 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'}}}
+load('jstests/aggregation/extras/utils.js'); // For 'assertErrorCode'.
+load('jstests/libs/fixture_helpers.js'); // For 'FixtureHelpers'
+
+const coll = db.server11675;
+coll.drop();
+
+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}));
+
+assert.commandWorked(coll.createIndex({text: "text"}));
+
+// query should have subfields query, project, sort, skip and limit. All but query are optional.
+const assertSameAsFind = function(query) {
+ let cursor = coll.find(query.query);
+ const pipeline = [{$match: query.query}];
+
+ if ('project' in query) {
+ cursor = coll.find(query.query, query.project); // no way to add to constructed cursor
+ pipeline.push({$project: query.project});
+ }
+
+ if ('sort' in query) {
+ cursor = cursor.sort(query.sort);
+ pipeline.push({$sort: query.sort});
+ }
+
+ if ('skip' in query) {
+ cursor = cursor.skip(query.skip);
+ pipeline.push({$skip: query.skip});
+ }
+
+ if ('limit' in query) {
+ cursor = cursor.limit(query.limit);
+ pipeline.push({$limit: query.limit});
+ }
+
+ 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
+ // client side, so that the results still count as equal.
+ if (!query.hasOwnProperty("sort")) {
+ findRes.sort(function(a, b) {
+ return a._id - b._id;
+ });
+ aggRes.sort(function(a, b) {
+ return a._id - b._id;
+ });
+ }
+
+ assert.docEq(aggRes, findRes);
+};
+
+assertSameAsFind({query: {}}); // sanity check
+assertSameAsFind({query: {$text: {$search: "apple"}}});
+assertSameAsFind({query: {_id: 1, $text: {$search: "apple"}}});
+assertSameAsFind(
+ {query: {$text: {$search: "apple"}}, project: {_id: 1, score: {$meta: "textScore"}}});
+assertSameAsFind(
+ {query: {$text: {$search: "apple banana"}}, project: {_id: 1, score: {$meta: "textScore"}}});
+assertSameAsFind({
+ query: {$text: {$search: "apple banana"}},
+ project: {_id: 1, score: {$meta: "textScore"}},
+ sort: {score: {$meta: "textScore"}}
+});
+assertSameAsFind({
+ query: {$text: {$search: "apple banana"}},
+ project: {_id: 1, score: {$meta: "textScore"}},
+ sort: {score: {$meta: "textScore"}},
+ limit: 1
+});
+assertSameAsFind({
+ query: {$text: {$search: "apple banana"}},
+ project: {_id: 1, score: {$meta: "textScore"}},
+ sort: {score: {$meta: "textScore"}},
+ skip: 1
+});
+assertSameAsFind({
+ query: {$text: {$search: "apple banana"}},
+ project: {_id: 1, score: {$meta: "textScore"}},
+ sort: {score: {$meta: "textScore"}},
+ skip: 1,
+ limit: 1
+});
+
+// $meta sort specification should be rejected if it has additional keys.
+assert.throws(function() {
+ 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() {
+ 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() {
+ 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() {
+ 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 = 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;
+ });
+let res = coll.aggregate([
+ {$match: {$text: {$search: 'apple banana'}}},
+ {$sort: {textScore: {$meta: 'textScore'}}}
])
.toArray();
- assert.eq(res[0].scoreOnMerger, score);
-
- // Make sure metadata works if first $project doesn't use it.
- 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.
- 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
- 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
- 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(
- coll, [{$sort: {text: 1}}, {$match: {$text: {$search: 'apple banana'}}}], 17313);
-
- // wrong $stage, but correct position
- assertErrorCode(coll,
- [{$project: {searchValue: {$text: {$search: 'apple banana'}}}}],
- ErrorCodes.InvalidPipelineOperator);
- assertErrorCode(coll, [{$sort: {$text: {$search: 'apple banana'}}}], 17312);
+assert.eq(res, findRes);
+
+// Make sure {$meta: 'textScore'} can be used as a sub-expression
+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
+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
+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);
+let score = res[0].scoreOnMerger; // save for later tests
+
+// Make sure metadata crosses shard -> merger boundary even if not used on shard
+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.
+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.
+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
+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
+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(coll, [{$sort: {text: 1}}, {$match: {$text: {$search: 'apple banana'}}}], 17313);
+
+// wrong $stage, but correct position
+assertErrorCode(coll,
+ [{$project: {searchValue: {$text: {$search: 'apple banana'}}}}],
+ ErrorCodes.InvalidPipelineOperator);
+assertErrorCode(coll, [{$sort: {$text: {$search: 'apple banana'}}}], 17312);
})();
diff --git a/jstests/aggregation/bugs/server12015.js b/jstests/aggregation/bugs/server12015.js
index 1b59a59545c..2c2b34d126c 100644
--- a/jstests/aggregation/bugs/server12015.js
+++ b/jstests/aggregation/bugs/server12015.js
@@ -9,77 +9,79 @@
load("jstests/aggregation/extras/utils.js"); // For orderedArrayEq.
(function() {
- "use strict";
- const coll = db.server12015;
- coll.drop();
- const indexSpec = {a: 1, b: 1};
+"use strict";
+const coll = db.server12015;
+coll.drop();
+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}));
- assert.writeOK(coll.insert({_id: 2, a: 1, b: 0}));
- assert.writeOK(coll.insert({_id: 3, a: 1, b: 1}));
+assert.writeOK(coll.insert({_id: 0, a: 0, b: 0}));
+assert.writeOK(coll.insert({_id: 1, a: 0, b: 1}));
+assert.writeOK(coll.insert({_id: 2, a: 1, b: 0}));
+assert.writeOK(coll.insert({_id: 3, a: 1, b: 1}));
- /**
- * Helper to test that for a given pipeline, the same results are returned whether or not an
- * index is present. If 'ignoreSortOrder' is present, test for result parity without assuming
- * the order of results.
- */
- 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);
+/**
+ * Helper to test that for a given pipeline, the same results are returned whether or not an
+ * index is present. If 'ignoreSortOrder' is present, test for result parity without assuming
+ * the order of results.
+ */
+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);
- // Once with an index.
- assert.commandWorked(coll.ensureIndex(indexSpec));
- var resultsWithIndex = coll.aggregate(pipeline).toArray();
+ // Once with an index.
+ assert.commandWorked(coll.ensureIndex(indexSpec));
+ var resultsWithIndex = coll.aggregate(pipeline).toArray();
- // Again without an index.
- assert.commandWorked(coll.dropIndex(indexSpec));
- var resultsWithoutIndex = coll.aggregate(pipeline).toArray();
+ // Again without an index.
+ assert.commandWorked(coll.dropIndex(indexSpec));
+ var resultsWithoutIndex = coll.aggregate(pipeline).toArray();
- if (ignoreSortOrder) {
- assert(arrayEq(resultsWithIndex, resultsWithoutIndex), tojson({
- resultsWithIndex: resultsWithIndex,
- resultsWithoutIndex: resultsWithoutIndex
- }));
- } else {
- assert.eq(resultsWithIndex, resultsWithoutIndex);
- }
+ if (ignoreSortOrder) {
+ assert(
+ arrayEq(resultsWithIndex, resultsWithoutIndex),
+ tojson({resultsWithIndex: resultsWithIndex, resultsWithoutIndex: resultsWithoutIndex}));
+ } else {
+ assert.eq(resultsWithIndex, resultsWithoutIndex);
}
+}
- // Uncovered $project, no $sort.
- const ignoreSortOrder = true;
- assertResultsMatch([{$project: {_id: 1, a: 1, b: 1}}], ignoreSortOrder);
+// Uncovered $project, no $sort.
+const ignoreSortOrder = true;
+assertResultsMatch([{$project: {_id: 1, a: 1, b: 1}}], ignoreSortOrder);
- // Covered $project, no $sort.
- 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);
+// Covered $project, no $sort.
+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}}]);
- assertResultsMatch([{$sort: {a: 1, b: 1}}, {$project: {_id: 1, a: 1, b: 1}}]);
- assertResultsMatch(
- [{$sort: {a: 1, b: 1}}, {$group: {_id: "$_id", arr: {$push: "$a"}, sum: {$sum: "$b"}}}],
- ignoreSortOrder);
+// Non-blocking $sort, uncovered $project.
+assertResultsMatch([{$sort: {a: -1, b: -1}}, {$project: {_id: 1, a: 1, b: 1}}]);
+assertResultsMatch([{$sort: {a: 1, b: 1}}, {$project: {_id: 1, a: 1, b: 1}}]);
+assertResultsMatch(
+ [{$sort: {a: 1, b: 1}}, {$group: {_id: "$_id", arr: {$push: "$a"}, sum: {$sum: "$b"}}}],
+ ignoreSortOrder);
- // Non-blocking $sort, covered $project.
- assertResultsMatch([{$sort: {a: -1, b: -1}}, {$project: {_id: 0, a: 1, b: 1}}]);
- assertResultsMatch([{$sort: {a: 1, b: 1}}, {$project: {_id: 0, a: 1, b: 1}}]);
- assertResultsMatch([{$sort: {a: 1, b: 1}}, {$group: {_id: "$b", arr: {$push: "$a"}}}],
- ignoreSortOrder);
+// Non-blocking $sort, covered $project.
+assertResultsMatch([{$sort: {a: -1, b: -1}}, {$project: {_id: 0, a: 1, b: 1}}]);
+assertResultsMatch([{$sort: {a: 1, b: 1}}, {$project: {_id: 0, a: 1, b: 1}}]);
+assertResultsMatch([{$sort: {a: 1, b: 1}}, {$group: {_id: "$b", arr: {$push: "$a"}}}],
+ ignoreSortOrder);
- // Blocking $sort, uncovered $project.
- assertResultsMatch([{$sort: {b: 1, a: -1}}, {$project: {_id: 1, a: 1, b: 1}}]);
- assertResultsMatch(
- [{$sort: {b: 1, a: -1}}, {$group: {_id: "$_id", arr: {$push: "$a"}, sum: {$sum: "$b"}}}],
- ignoreSortOrder);
+// Blocking $sort, uncovered $project.
+assertResultsMatch([{$sort: {b: 1, a: -1}}, {$project: {_id: 1, a: 1, b: 1}}]);
+assertResultsMatch(
+ [{$sort: {b: 1, a: -1}}, {$group: {_id: "$_id", arr: {$push: "$a"}, sum: {$sum: "$b"}}}],
+ ignoreSortOrder);
- // Blocking $sort, covered $project.
- assertResultsMatch([{$sort: {b: 1, a: -1}}, {$project: {_id: 0, a: 1, b: 1}}]);
- assertResultsMatch([{$sort: {b: 1, a: -1}}, {$group: {_id: "$b", arr: {$push: "$a"}}}],
- ignoreSortOrder);
+// Blocking $sort, covered $project.
+assertResultsMatch([{$sort: {b: 1, a: -1}}, {$project: {_id: 0, a: 1, b: 1}}]);
+assertResultsMatch([{$sort: {b: 1, a: -1}}, {$group: {_id: "$b", arr: {$push: "$a"}}}],
+ ignoreSortOrder);
}());
diff --git a/jstests/aggregation/bugs/server14421.js b/jstests/aggregation/bugs/server14421.js
index 3201e20a81a..b6701546e3d 100644
--- a/jstests/aggregation/bugs/server14421.js
+++ b/jstests/aggregation/bugs/server14421.js
@@ -1,40 +1,40 @@
// SERVER-14421 minDistance for $geoNear aggregation operator
(function() {
- 'use strict';
- var coll = db.mindistance;
- coll.drop();
- assert.writeOK(coll.insert([
- {_id: 0, loc: {type: "Point", coordinates: [0, 0]}},
- {_id: 1, loc: {type: "Point", coordinates: [0, 0.01]}}
- ]));
- var response = coll.createIndex({loc: "2dsphere"});
- assert.eq(response.ok, 1, "Could not create 2dsphere index");
- var results = coll.aggregate([{
- $geoNear: {
- minDistance: 10000,
- spherical: true,
- distanceField: "distance",
- near: {type: "Point", coordinates: [0, 0]}
- }
- }]);
- assert.eq(results.itcount(), 0);
- results = coll.aggregate([{
- $geoNear: {
- minDistance: 1,
- spherical: true,
- distanceField: "distance",
- near: {type: "Point", coordinates: [0, 0]}
- }
- }]);
- assert.eq(results.itcount(), 1);
- results = coll.aggregate([{
- $geoNear: {
- minDistance: 0,
- spherical: true,
- distanceField: "distance",
- near: {type: "Point", coordinates: [0, 0]}
- }
- }]);
- assert.eq(results.itcount(), 2);
- coll.drop();
+'use strict';
+var coll = db.mindistance;
+coll.drop();
+assert.writeOK(coll.insert([
+ {_id: 0, loc: {type: "Point", coordinates: [0, 0]}},
+ {_id: 1, loc: {type: "Point", coordinates: [0, 0.01]}}
+]));
+var response = coll.createIndex({loc: "2dsphere"});
+assert.eq(response.ok, 1, "Could not create 2dsphere index");
+var results = coll.aggregate([{
+ $geoNear: {
+ minDistance: 10000,
+ spherical: true,
+ distanceField: "distance",
+ near: {type: "Point", coordinates: [0, 0]}
+ }
+}]);
+assert.eq(results.itcount(), 0);
+results = coll.aggregate([{
+ $geoNear: {
+ minDistance: 1,
+ spherical: true,
+ distanceField: "distance",
+ near: {type: "Point", coordinates: [0, 0]}
+ }
+}]);
+assert.eq(results.itcount(), 1);
+results = coll.aggregate([{
+ $geoNear: {
+ minDistance: 0,
+ spherical: true,
+ distanceField: "distance",
+ near: {type: "Point", coordinates: [0, 0]}
+ }
+}]);
+assert.eq(results.itcount(), 2);
+coll.drop();
}()); \ No newline at end of file
diff --git a/jstests/aggregation/bugs/server14670.js b/jstests/aggregation/bugs/server14670.js
index dc8a750e9db..adadb154da0 100644
--- a/jstests/aggregation/bugs/server14670.js
+++ b/jstests/aggregation/bugs/server14670.js
@@ -3,21 +3,19 @@
load("jstests/aggregation/extras/utils.js"); // For assertErrorCode.
(function() {
- "use strict";
+"use strict";
- var coll = db.substr;
- coll.drop();
+var coll = db.substr;
+coll.drop();
- // Need an empty document for the pipeline.
- coll.insert({});
+// Need an empty document for the pipeline.
+coll.insert({});
- assertErrorCode(coll,
- [{$project: {strLen: {$strLenBytes: 1}}}],
- 34473,
- "$strLenBytes requires a string argument.");
+assertErrorCode(coll,
+ [{$project: {strLen: {$strLenBytes: 1}}}],
+ 34473,
+ "$strLenBytes requires a string argument.");
- assertErrorCode(coll,
- [{$project: {strLen: {$strLenCP: 1}}}],
- 34471,
- "$strLenCP requires a string argument.");
+assertErrorCode(
+ coll, [{$project: {strLen: {$strLenCP: 1}}}], 34471, "$strLenCP requires a string argument.");
}());
diff --git a/jstests/aggregation/bugs/server14691.js b/jstests/aggregation/bugs/server14691.js
index 0ba010ac41a..2703f2dead9 100644
--- a/jstests/aggregation/bugs/server14691.js
+++ b/jstests/aggregation/bugs/server14691.js
@@ -1,52 +1,52 @@
// SERVER-14691: $avg aggregator should return null when it receives no input.
(function() {
- 'use strict';
+'use strict';
- var coll = db.accumulate_avg_sum_null;
+var coll = db.accumulate_avg_sum_null;
- // Test the $avg aggregator.
- coll.drop();
+// Test the $avg aggregator.
+coll.drop();
- // Null cases.
- assert.writeOK(coll.insert({a: 1, b: 2, c: 'string', d: null}));
+// Null cases.
+assert.writeOK(coll.insert({a: 1, b: 2, c: 'string', d: null}));
- // Missing field.
- var pipeline = [{$group: {_id: '$a', avg: {$avg: '$missing'}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{_id: 1, avg: null}]);
+// Missing field.
+var pipeline = [{$group: {_id: '$a', avg: {$avg: '$missing'}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{_id: 1, avg: null}]);
- // Non-numeric field.
- pipeline = [{$group: {_id: '$a', avg: {$avg: '$c'}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{_id: 1, avg: null}]);
+// Non-numeric field.
+pipeline = [{$group: {_id: '$a', avg: {$avg: '$c'}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{_id: 1, avg: null}]);
- // Field with value of null.
- pipeline = [{$group: {_id: '$a', avg: {$avg: '$d'}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{_id: 1, avg: null}]);
+// Field with value of null.
+pipeline = [{$group: {_id: '$a', avg: {$avg: '$d'}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{_id: 1, avg: null}]);
- // All three.
- coll.insert({a: 1, d: 'string'});
- coll.insert({a: 1});
- pipeline = [{$group: {_id: '$a', avg: {$avg: '$d'}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{_id: 1, avg: null}]);
+// All three.
+coll.insert({a: 1, d: 'string'});
+coll.insert({a: 1});
+pipeline = [{$group: {_id: '$a', avg: {$avg: '$d'}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{_id: 1, avg: null}]);
- // Non-null cases.
- coll.drop();
- assert.writeOK(coll.insert({a: 1, b: 2}));
- pipeline = [{$group: {_id: '$a', avg: {$avg: '$b'}}}];
+// Non-null cases.
+coll.drop();
+assert.writeOK(coll.insert({a: 1, b: 2}));
+pipeline = [{$group: {_id: '$a', avg: {$avg: '$b'}}}];
- // One field.
- assert.eq(coll.aggregate(pipeline).toArray(), [{_id: 1, avg: 2}]);
+// One field.
+assert.eq(coll.aggregate(pipeline).toArray(), [{_id: 1, avg: 2}]);
- // Two fields.
- assert.writeOK(coll.insert({a: 1, b: 4}));
- assert.eq(coll.aggregate(pipeline).toArray(), [{_id: 1, avg: 3}]);
+// Two fields.
+assert.writeOK(coll.insert({a: 1, b: 4}));
+assert.eq(coll.aggregate(pipeline).toArray(), [{_id: 1, avg: 3}]);
- // Average of zero should still work.
- assert.writeOK(coll.insert({a: 1, b: -6}));
- assert.eq(coll.aggregate(pipeline).toArray(), [{_id: 1, avg: 0}]);
+// Average of zero should still work.
+assert.writeOK(coll.insert({a: 1, b: -6}));
+assert.eq(coll.aggregate(pipeline).toArray(), [{_id: 1, avg: 0}]);
- // Missing, null, or non-numeric fields should not error or affect the average.
- assert.writeOK(coll.insert({a: 1}));
- assert.writeOK(coll.insert({a: 1, b: 'string'}));
- assert.writeOK(coll.insert({a: 1, b: null}));
- assert.eq(coll.aggregate(pipeline).toArray(), [{_id: 1, avg: 0}]);
+// Missing, null, or non-numeric fields should not error or affect the average.
+assert.writeOK(coll.insert({a: 1}));
+assert.writeOK(coll.insert({a: 1, b: 'string'}));
+assert.writeOK(coll.insert({a: 1, b: null}));
+assert.eq(coll.aggregate(pipeline).toArray(), [{_id: 1, avg: 0}]);
}());
diff --git a/jstests/aggregation/bugs/server14872.js b/jstests/aggregation/bugs/server14872.js
index 3be4018ac21..4787df5259b 100644
--- a/jstests/aggregation/bugs/server14872.js
+++ b/jstests/aggregation/bugs/server14872.js
@@ -4,36 +4,36 @@
load('jstests/aggregation/extras/utils.js');
(function() {
- 'use strict';
+'use strict';
- var coll = db.agg_concat_arrays_expr;
- coll.drop();
+var coll = db.agg_concat_arrays_expr;
+coll.drop();
- assert.writeOK(coll.insert({a: [1, 2], b: ['three'], c: [], d: [[3], 4], e: null, str: 'x'}));
+assert.writeOK(coll.insert({a: [1, 2], b: ['three'], c: [], d: [[3], 4], e: null, str: 'x'}));
- // Basic concatenation.
- var pipeline = [{$project: {_id: 0, all: {$concatArrays: ['$a', '$b', '$c']}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{all: [1, 2, 'three']}]);
+// Basic concatenation.
+var pipeline = [{$project: {_id: 0, all: {$concatArrays: ['$a', '$b', '$c']}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{all: [1, 2, 'three']}]);
- // Concatenation with nested arrays.
- pipeline = [{$project: {_id: 0, all: {$concatArrays: ['$a', '$d']}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{all: [1, 2, [3], 4]}]);
+// Concatenation with nested arrays.
+pipeline = [{$project: {_id: 0, all: {$concatArrays: ['$a', '$d']}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{all: [1, 2, [3], 4]}]);
- // Concatenation with 1 argument.
- pipeline = [{$project: {_id: 0, all: {$concatArrays: ['$a']}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{all: [1, 2]}]);
+// Concatenation with 1 argument.
+pipeline = [{$project: {_id: 0, all: {$concatArrays: ['$a']}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{all: [1, 2]}]);
- // Concatenation with no arguments.
- pipeline = [{$project: {_id: 0, all: {$concatArrays: []}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{all: []}]);
+// Concatenation with no arguments.
+pipeline = [{$project: {_id: 0, all: {$concatArrays: []}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{all: []}]);
- // Any nullish inputs will result in null.
- pipeline = [{$project: {_id: 0, all: {$concatArrays: ['$a', '$e']}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{all: null}]);
- pipeline = [{$project: {_id: 0, all: {$concatArrays: ['$a', '$f']}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{all: null}]);
+// Any nullish inputs will result in null.
+pipeline = [{$project: {_id: 0, all: {$concatArrays: ['$a', '$e']}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{all: null}]);
+pipeline = [{$project: {_id: 0, all: {$concatArrays: ['$a', '$f']}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{all: null}]);
- // Error on any non-array, non-null inputs.
- pipeline = [{$project: {_id: 0, all: {$concatArrays: ['$a', '$str']}}}];
- assertErrorCode(coll, pipeline, 28664);
+// Error on any non-array, non-null inputs.
+pipeline = [{$project: {_id: 0, all: {$concatArrays: ['$a', '$str']}}}];
+assertErrorCode(coll, pipeline, 28664);
}());
diff --git a/jstests/aggregation/bugs/server17224.js b/jstests/aggregation/bugs/server17224.js
index 888c99b808c..31d0e889b8c 100644
--- a/jstests/aggregation/bugs/server17224.js
+++ b/jstests/aggregation/bugs/server17224.js
@@ -1,25 +1,25 @@
// SERVER-17224 An aggregation result with exactly the right size could crash the server rather than
// returning an error.
(function() {
- 'use strict';
+'use strict';
- var t = db.server17224;
- t.drop();
+var t = db.server17224;
+t.drop();
- // first 63MB
- for (var i = 0; i < 63; i++) {
- t.insert({a: new Array(1024 * 1024 + 1).join('a')});
- }
+// first 63MB
+for (var i = 0; i < 63; i++) {
+ t.insert({a: new Array(1024 * 1024 + 1).join('a')});
+}
- // the remaining ~1MB with room for field names and other overhead
- t.insert({a: new Array(1024 * 1024 - 1105).join('a')});
+// the remaining ~1MB with room for field names and other overhead
+t.insert({a: new Array(1024 * 1024 - 1105).join('a')});
- // do not use cursor form, since it has a different workaroud for this issue.
- assert.commandFailed(db.runCommand({
- aggregate: t.getName(),
- pipeline: [{$match: {}}, {$group: {_id: null, arr: {$push: {a: '$a'}}}}]
- }));
+// do not use cursor form, since it has a different workaroud for this issue.
+assert.commandFailed(db.runCommand({
+ aggregate: t.getName(),
+ pipeline: [{$match: {}}, {$group: {_id: null, arr: {$push: {a: '$a'}}}}]
+}));
- // Make sure the server is still up.
- assert.commandWorked(db.runCommand('ping'));
+// Make sure the server is still up.
+assert.commandWorked(db.runCommand('ping'));
}());
diff --git a/jstests/aggregation/bugs/server17943.js b/jstests/aggregation/bugs/server17943.js
index 075623c705d..6b510e2ddbc 100644
--- a/jstests/aggregation/bugs/server17943.js
+++ b/jstests/aggregation/bugs/server17943.js
@@ -4,80 +4,88 @@
load('jstests/aggregation/extras/utils.js');
(function() {
- 'use strict';
+'use strict';
- var coll = db.agg_filter_expr;
- coll.drop();
+var coll = db.agg_filter_expr;
+coll.drop();
- assert.writeOK(coll.insert({_id: 0, a: [1, 2, 3, 4, 5]}));
- assert.writeOK(coll.insert({_id: 1, a: [2, 4]}));
- assert.writeOK(coll.insert({_id: 2, a: []}));
- assert.writeOK(coll.insert({_id: 3, a: [1]}));
- assert.writeOK(coll.insert({_id: 4, a: null}));
- assert.writeOK(coll.insert({_id: 5, a: undefined}));
- assert.writeOK(coll.insert({_id: 6}));
+assert.writeOK(coll.insert({_id: 0, a: [1, 2, 3, 4, 5]}));
+assert.writeOK(coll.insert({_id: 1, a: [2, 4]}));
+assert.writeOK(coll.insert({_id: 2, a: []}));
+assert.writeOK(coll.insert({_id: 3, a: [1]}));
+assert.writeOK(coll.insert({_id: 4, a: null}));
+assert.writeOK(coll.insert({_id: 5, a: undefined}));
+assert.writeOK(coll.insert({_id: 6}));
- // Create filter to only accept odd numbers.
- filterDoc = {input: '$a', as: 'x', cond: {$eq: [1, {$mod: ['$$x', 2]}]}};
- var expectedResults = [
- {_id: 0, b: [1, 3, 5]},
- {_id: 1, b: []},
- {_id: 2, b: []},
- {_id: 3, b: [1]},
- {_id: 4, b: null},
- {_id: 5, b: null},
- {_id: 6, b: null},
- ];
- var results =
- coll.aggregate([{$project: {b: {$filter: filterDoc}}}, {$sort: {_id: 1}}]).toArray();
- assert.eq(results, expectedResults);
+// Create filter to only accept odd numbers.
+filterDoc = {input: '$a', as: 'x', cond: {$eq: [1, {$mod: ['$$x', 2]}]}};
+var expectedResults = [
+ {_id: 0, b: [1, 3, 5]},
+ {_id: 1, b: []},
+ {_id: 2, b: []},
+ {_id: 3, b: [1]},
+ {_id: 4, b: null},
+ {_id: 5, b: null},
+ {_id: 6, b: null},
+];
+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'
- filterDoc = {input: '$a', cond: {$eq: [2, '$$this']}};
- expectedResults = [
- {_id: 0, b: [2]},
- {_id: 1, b: [2]},
- {_id: 2, b: []},
- {_id: 3, b: []},
- {_id: 4, b: null},
- {_id: 5, b: null},
- {_id: 6, b: null},
- ];
- 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'
+filterDoc = {
+ input: '$a',
+ cond: {$eq: [2, '$$this']}
+};
+expectedResults = [
+ {_id: 0, b: [2]},
+ {_id: 1, b: [2]},
+ {_id: 2, b: []},
+ {_id: 3, b: []},
+ {_id: 4, b: null},
+ {_id: 5, b: null},
+ {_id: 6, b: null},
+];
+results = coll.aggregate([{$project: {b: {$filter: filterDoc}}}, {$sort: {_id: 1}}]).toArray();
+assert.eq(results, expectedResults);
- // Invalid filter expressions.
+// Invalid filter expressions.
- // '$filter' is not a document.
- var filterDoc = 'string';
- assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 28646);
+// '$filter' is not a document.
+var filterDoc = 'string';
+assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 28646);
- // Extra field(s).
- filterDoc = {input: '$a', as: 'x', cond: true, extra: 1};
- assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 28647);
+// Extra field(s).
+filterDoc = {input: '$a', as: 'x', cond: true, extra: 1};
+assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 28647);
- // Missing 'input'.
- filterDoc = {as: 'x', cond: true};
- assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 28648);
+// Missing 'input'.
+filterDoc = {
+ as: 'x',
+ cond: true
+};
+assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 28648);
- // Missing 'cond'.
- filterDoc = {input: '$a', as: 'x'};
- assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 28650);
+// Missing 'cond'.
+filterDoc = {input: '$a', as: 'x'};
+assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 28650);
- // 'as' is not a valid variable name.
- filterDoc = {input: '$a', as: '$x', cond: true};
- assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 16867);
+// 'as' is not a valid variable name.
+filterDoc = {input: '$a', as: '$x', cond: true};
+assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 16867);
- // 'input' is not an array.
- filterDoc = {input: 'string', as: 'x', cond: true};
- assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 28651);
+// 'input' is not an array.
+filterDoc = {input: 'string', as: 'x', cond: true};
+assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 28651);
- // 'cond' uses undefined variable name.
- filterDoc = {input: '$a', cond: {$eq: [1, '$$var']}};
- assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 17276);
+// 'cond' uses undefined variable name.
+filterDoc = {
+ input: '$a',
+ cond: {$eq: [1, '$$var']}
+};
+assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 17276);
- assert(coll.drop());
- assert.writeOK(coll.insert({a: 'string'}));
- filterDoc = {input: '$a', as: 'x', cond: true};
- assertErrorCode(coll, [{$project: {b: {$filter: filterDoc}}}], 28651);
+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/server18198.js b/jstests/aggregation/bugs/server18198.js
index a182195a864..9aa26451161 100644
--- a/jstests/aggregation/bugs/server18198.js
+++ b/jstests/aggregation/bugs/server18198.js
@@ -1,67 +1,67 @@
// SERVER-18198 check read pref is only applied when there is no $out stage
// in aggregate shell helper
(function() {
- "use strict";
- var t = db.server18198;
- t.drop();
+"use strict";
+var t = db.server18198;
+t.drop();
- var mongo = db.getMongo();
+var mongo = db.getMongo();
- try {
- var commandsRan = [];
- // hook in our patched mongo
- var mockMongo = {
- getSlaveOk: function() {
- return true;
- },
- runCommand: function(db, cmd, opts) {
- commandsRan.push({db: db, cmd: cmd, opts: opts});
- return {ok: 1.0};
- },
- getReadPref: function() {
- return {mode: "secondaryPreferred"};
- },
- getReadPrefMode: function() {
- return "secondaryPreferred";
- },
- getMinWireVersion: function() {
- return mongo.getMinWireVersion();
- },
- getMaxWireVersion: function() {
- return mongo.getMaxWireVersion();
- },
- isReplicaSetMember: function() {
- return mongo.isReplicaSetMember();
- },
- isMongos: function() {
- return mongo.isMongos();
- },
- isCausalConsistency: function() {
- return false;
- },
- getClusterTime: function() {
- return mongo.getClusterTime();
- },
- };
+try {
+ var commandsRan = [];
+ // hook in our patched mongo
+ var mockMongo = {
+ getSlaveOk: function() {
+ return true;
+ },
+ runCommand: function(db, cmd, opts) {
+ commandsRan.push({db: db, cmd: cmd, opts: opts});
+ return {ok: 1.0};
+ },
+ getReadPref: function() {
+ return {mode: "secondaryPreferred"};
+ },
+ getReadPrefMode: function() {
+ return "secondaryPreferred";
+ },
+ getMinWireVersion: function() {
+ return mongo.getMinWireVersion();
+ },
+ getMaxWireVersion: function() {
+ return mongo.getMaxWireVersion();
+ },
+ isReplicaSetMember: function() {
+ return mongo.isReplicaSetMember();
+ },
+ isMongos: function() {
+ return mongo.isMongos();
+ },
+ isCausalConsistency: function() {
+ return false;
+ },
+ getClusterTime: function() {
+ return mongo.getClusterTime();
+ },
+ };
- db._mongo = mockMongo;
- db._session = new _DummyDriverSession(mockMongo);
+ db._mongo = mockMongo;
+ db._session = new _DummyDriverSession(mockMongo);
- // this query should not get a read pref
- t.aggregate([{$sort: {"x": 1}}, {$out: "foo"}]);
- assert.eq(commandsRan.length, 1);
- // check that it doesn't have a read preference
- assert(!commandsRan[0].cmd.hasOwnProperty("$readPreference"));
+ // this query should not get a read pref
+ t.aggregate([{$sort: {"x": 1}}, {$out: "foo"}]);
+ assert.eq(commandsRan.length, 1);
+ // check that it doesn't have a read preference
+ assert(!commandsRan[0].cmd.hasOwnProperty("$readPreference"));
- commandsRan = [];
+ commandsRan = [];
- t.aggregate([{$sort: {"x": 1}}]);
- // check another command was run
- assert.eq(commandsRan.length, 1);
- // check that it has a read preference
- assert(commandsRan[0].cmd.hasOwnProperty("$readPreference"));
- } finally {
- db._mongo = mongo;
- db._session = new _DummyDriverSession(mongo);
- }
+ t.aggregate([{$sort: {"x": 1}}]);
+ // check another command was run
+ assert.eq(commandsRan.length, 1);
+ // check that it has a read preference
+ assert(commandsRan[0].cmd.hasOwnProperty("$readPreference"));
+} finally {
+ db._mongo = mongo;
+ db._session = new _DummyDriverSession(mongo);
+}
})();
diff --git a/jstests/aggregation/bugs/server18222.js b/jstests/aggregation/bugs/server18222.js
index cea52b3970d..d27188bbb2b 100644
--- a/jstests/aggregation/bugs/server18222.js
+++ b/jstests/aggregation/bugs/server18222.js
@@ -1,43 +1,43 @@
// SERVER-18222: Add $isArray aggregation expression.
(function() {
- 'use strict';
- var coll = db.is_array_expr;
- coll.drop();
+'use strict';
+var coll = db.is_array_expr;
+coll.drop();
- // Non-array types.
- assert.writeOK(coll.insert({_id: 0, x: 0}));
- assert.writeOK(coll.insert({_id: 1, x: '0'}));
- assert.writeOK(coll.insert({_id: 2, x: new ObjectId()}));
- assert.writeOK(coll.insert({_id: 3, x: new NumberLong(0)}));
- assert.writeOK(coll.insert({_id: 4, x: {y: []}}));
- assert.writeOK(coll.insert({_id: 5, x: null}));
- assert.writeOK(coll.insert({_id: 6, x: NaN}));
- assert.writeOK(coll.insert({_id: 7, x: undefined}));
+// Non-array types.
+assert.writeOK(coll.insert({_id: 0, x: 0}));
+assert.writeOK(coll.insert({_id: 1, x: '0'}));
+assert.writeOK(coll.insert({_id: 2, x: new ObjectId()}));
+assert.writeOK(coll.insert({_id: 3, x: new NumberLong(0)}));
+assert.writeOK(coll.insert({_id: 4, x: {y: []}}));
+assert.writeOK(coll.insert({_id: 5, x: null}));
+assert.writeOK(coll.insert({_id: 6, x: NaN}));
+assert.writeOK(coll.insert({_id: 7, x: undefined}));
- // Array types.
- assert.writeOK(coll.insert({_id: 8, x: []}));
- assert.writeOK(coll.insert({_id: 9, x: [0]}));
- assert.writeOK(coll.insert({_id: 10, x: ['0']}));
+// Array types.
+assert.writeOK(coll.insert({_id: 8, x: []}));
+assert.writeOK(coll.insert({_id: 9, x: [0]}));
+assert.writeOK(coll.insert({_id: 10, x: ['0']}));
- // Project field is_array to represent whether the field x was an array.
- var results = coll.aggregate([
- {$sort: {_id: 1}},
- {$project: {isArray: {$isArray: '$x'}}},
- ])
- .toArray();
- var expectedResults = [
- {_id: 0, isArray: false},
- {_id: 1, isArray: false},
- {_id: 2, isArray: false},
- {_id: 3, isArray: false},
- {_id: 4, isArray: false},
- {_id: 5, isArray: false},
- {_id: 6, isArray: false},
- {_id: 7, isArray: false},
- {_id: 8, isArray: true},
- {_id: 9, isArray: true},
- {_id: 10, isArray: true},
- ];
+// Project field is_array to represent whether the field x was an array.
+var results = coll.aggregate([
+ {$sort: {_id: 1}},
+ {$project: {isArray: {$isArray: '$x'}}},
+ ])
+ .toArray();
+var expectedResults = [
+ {_id: 0, isArray: false},
+ {_id: 1, isArray: false},
+ {_id: 2, isArray: false},
+ {_id: 3, isArray: false},
+ {_id: 4, isArray: false},
+ {_id: 5, isArray: false},
+ {_id: 6, isArray: false},
+ {_id: 7, isArray: false},
+ {_id: 8, isArray: true},
+ {_id: 9, isArray: true},
+ {_id: 10, isArray: true},
+];
- assert.eq(results, expectedResults);
+assert.eq(results, expectedResults);
}());
diff --git a/jstests/aggregation/bugs/server18427.js b/jstests/aggregation/bugs/server18427.js
index f15c1f9e23e..fffbc51ef64 100644
--- a/jstests/aggregation/bugs/server18427.js
+++ b/jstests/aggregation/bugs/server18427.js
@@ -4,156 +4,151 @@
load('jstests/aggregation/extras/utils.js');
(function() {
- 'use strict';
- var coll = db.log_exponential_expressions;
- coll.drop();
- assert.writeOK(coll.insert({_id: 0}));
-
- 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);
-
- // 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);
+'use strict';
+var coll = db.log_exponential_expressions;
+coll.drop();
+assert.writeOK(coll.insert({_id: 0}));
+
+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);
+
+// 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/server20163.js b/jstests/aggregation/bugs/server20163.js
index e61ba606c24..a03e3c70fbe 100644
--- a/jstests/aggregation/bugs/server20163.js
+++ b/jstests/aggregation/bugs/server20163.js
@@ -3,138 +3,204 @@
load("jstests/aggregation/extras/utils.js"); // For assertErrorCode.
(function() {
- "use strict";
-
- var coll = db.zip;
- coll.drop();
-
- coll.insert({'long': [1, 2, 3], 'short': ['x', 'y']});
-
- var zipObj = 3;
- assertErrorCode(coll,
- [{$project: {zipped: {$zip: zipObj}}}],
- 34460,
- "$zip requires an object" + " as an argument.");
-
- zipObj = {inputs: []};
- assertErrorCode(coll,
- [{$project: {zipped: {$zip: zipObj}}}],
- 34465,
- "$zip requires at least" + " one input array");
-
- zipObj = {inputs: {"a": "b"}};
- assertErrorCode(coll, [{$project: {zipped: {$zip: zipObj}}}], 34461, "inputs is not an array");
-
- zipObj = {inputs: ["$a"], defaults: ["A"]};
- assertErrorCode(coll,
- [{$project: {zipped: {$zip: zipObj}}}],
- 34466,
- "cannot specify defaults" + " unless useLongestLength is true.");
-
- zipObj = {inputs: ["$a"], defaults: ["A", "B"], useLongestLength: true};
- assertErrorCode(coll,
- [{$project: {zipped: {$zip: zipObj}}}],
- 34467,
- "inputs and defaults" + " must be the same length.");
-
- zipObj = {inputs: ["$a"], defaults: {"a": "b"}};
- assertErrorCode(
- coll, [{$project: {zipped: {$zip: zipObj}}}], 34462, "defaults is not an" + " array");
-
- zipObj = {inputs: ["$a"], defaults: ["A"], useLongestLength: 1};
- assertErrorCode(
- coll, [{$project: {zipped: {$zip: zipObj}}}], 34463, "useLongestLength is not" + " a bool");
-
- zipObj = {inputs: ["$a", "$b"], defaults: ["A"], notAField: 1};
- assertErrorCode(coll, [{$project: {zipped: {$zip: zipObj}}}], 34464, "unknown argument");
-
- zipObj = {inputs: ["A", "B"]};
- assertErrorCode(coll,
- [{$project: {zipped: {$zip: zipObj}}}],
- 34468,
- "an element of inputs" + " was not an array.");
-
- zipObj = {inputs: [[1, 2, 3], ["A", "B", "C"]]};
- var res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
- var output = res.toArray();
- assert.eq(1, output.length);
- assert.eq(output[0].zipped, [[1, "A"], [2, "B"], [3, "C"]]);
-
- zipObj = {inputs: [[1, 2, 3], null]};
- res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
- output = res.toArray();
- assert.eq(1, output.length);
- assert.eq(output[0].zipped, null);
-
- zipObj = {inputs: [null, [1, 2, 3]]};
- res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
- output = res.toArray();
- assert.eq(1, output.length);
- assert.eq(output[0].zipped, null);
-
- zipObj = {inputs: ["$missing", [1, 2, 3]]};
- res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
- output = res.toArray();
- assert.eq(1, output.length);
- assert.eq(output[0].zipped, null);
-
- zipObj = {inputs: [undefined, [1, 2, 3]]};
- res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
- output = res.toArray();
- assert.eq(1, output.length);
- assert.eq(output[0].zipped, null);
-
- zipObj = {inputs: [[1, 2, 3], ["A", "B"]]};
- res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
- output = res.toArray();
- assert.eq(1, output.length);
- assert.eq(output[0].zipped, [[1, "A"], [2, "B"]]);
-
- zipObj = {inputs: [["A", "B"], [1, 2, 3]]};
- res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
- output = res.toArray();
- assert.eq(1, output.length);
- assert.eq(output[0].zipped, [["A", 1], ["B", 2]]);
-
- zipObj = {inputs: [[], []]};
- res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
- output = res.toArray();
- assert.eq(1, output.length);
- assert.eq(output[0].zipped, []);
-
- zipObj = {inputs: [["$short"], ["$long"]]};
- res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
- output = res.toArray();
- assert.eq(1, output.length);
- assert.eq(output[0].zipped, [[['x', 'y'], [1, 2, 3]]]);
-
- zipObj = {inputs: ["$short", "$long"]};
- res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
- output = res.toArray();
- assert.eq(1, output.length);
- assert.eq(output[0].zipped, [['x', 1], ['y', 2]]);
-
- zipObj = {inputs: [["$long"]]};
- res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
- output = res.toArray();
- assert.eq(1, output.length);
- assert.eq(output[0].zipped, [[[1, 2, 3]]]);
-
- zipObj = {inputs: [[1, 2, 3], ['a', 'b', 'c'], ['c', 'b', 'a']]};
- res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
- output = res.toArray();
- assert.eq(1, output.length);
- assert.eq(output[0].zipped, [[1, 'a', 'c'], [2, 'b', 'b'], [3, 'c', 'a']]);
-
- zipObj = {inputs: [[1, 2, 3], ["A", "B"]], defaults: ["C", "D"], useLongestLength: true};
- res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
- output = res.toArray();
- assert.eq(1, output.length);
- assert.eq(output[0].zipped, [[1, "A"], [2, "B"], [3, "D"]]);
-
- zipObj = {inputs: [[1, 2, 3], ["A", "B"]], useLongestLength: true};
- res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
- output = res.toArray();
- assert.eq(1, output.length);
- assert.eq(output[0].zipped, [[1, "A"], [2, "B"], [3, null]]);
+"use strict";
+
+var coll = db.zip;
+coll.drop();
+
+coll.insert({'long': [1, 2, 3], 'short': ['x', 'y']});
+
+var zipObj = 3;
+assertErrorCode(coll,
+ [{$project: {zipped: {$zip: zipObj}}}],
+ 34460,
+ "$zip requires an object" +
+ " as an argument.");
+
+zipObj = {
+ inputs: []
+};
+assertErrorCode(coll,
+ [{$project: {zipped: {$zip: zipObj}}}],
+ 34465,
+ "$zip requires at least" +
+ " one input array");
+
+zipObj = {
+ inputs: {"a": "b"}
+};
+assertErrorCode(coll, [{$project: {zipped: {$zip: zipObj}}}], 34461, "inputs is not an array");
+
+zipObj = {
+ inputs: ["$a"],
+ defaults: ["A"]
+};
+assertErrorCode(coll,
+ [{$project: {zipped: {$zip: zipObj}}}],
+ 34466,
+ "cannot specify defaults" +
+ " unless useLongestLength is true.");
+
+zipObj = {
+ inputs: ["$a"],
+ defaults: ["A", "B"],
+ useLongestLength: true
+};
+assertErrorCode(coll,
+ [{$project: {zipped: {$zip: zipObj}}}],
+ 34467,
+ "inputs and defaults" +
+ " must be the same length.");
+
+zipObj = {
+ inputs: ["$a"],
+ defaults: {"a": "b"}
+};
+assertErrorCode(coll,
+ [{$project: {zipped: {$zip: zipObj}}}],
+ 34462,
+ "defaults is not an" +
+ " array");
+
+zipObj = {
+ inputs: ["$a"],
+ defaults: ["A"],
+ useLongestLength: 1
+};
+assertErrorCode(coll,
+ [{$project: {zipped: {$zip: zipObj}}}],
+ 34463,
+ "useLongestLength is not" +
+ " a bool");
+
+zipObj = {
+ inputs: ["$a", "$b"],
+ defaults: ["A"],
+ notAField: 1
+};
+assertErrorCode(coll, [{$project: {zipped: {$zip: zipObj}}}], 34464, "unknown argument");
+
+zipObj = {
+ inputs: ["A", "B"]
+};
+assertErrorCode(coll,
+ [{$project: {zipped: {$zip: zipObj}}}],
+ 34468,
+ "an element of inputs" +
+ " was not an array.");
+
+zipObj = {
+ inputs: [[1, 2, 3], ["A", "B", "C"]]
+};
+var res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
+var output = res.toArray();
+assert.eq(1, output.length);
+assert.eq(output[0].zipped, [[1, "A"], [2, "B"], [3, "C"]]);
+
+zipObj = {
+ inputs: [[1, 2, 3], null]
+};
+res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
+output = res.toArray();
+assert.eq(1, output.length);
+assert.eq(output[0].zipped, null);
+
+zipObj = {
+ inputs: [null, [1, 2, 3]]
+};
+res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
+output = res.toArray();
+assert.eq(1, output.length);
+assert.eq(output[0].zipped, null);
+
+zipObj = {
+ inputs: ["$missing", [1, 2, 3]]
+};
+res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
+output = res.toArray();
+assert.eq(1, output.length);
+assert.eq(output[0].zipped, null);
+
+zipObj = {
+ inputs: [undefined, [1, 2, 3]]
+};
+res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
+output = res.toArray();
+assert.eq(1, output.length);
+assert.eq(output[0].zipped, null);
+
+zipObj = {
+ inputs: [[1, 2, 3], ["A", "B"]]
+};
+res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
+output = res.toArray();
+assert.eq(1, output.length);
+assert.eq(output[0].zipped, [[1, "A"], [2, "B"]]);
+
+zipObj = {
+ inputs: [["A", "B"], [1, 2, 3]]
+};
+res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
+output = res.toArray();
+assert.eq(1, output.length);
+assert.eq(output[0].zipped, [["A", 1], ["B", 2]]);
+
+zipObj = {
+ inputs: [[], []]
+};
+res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
+output = res.toArray();
+assert.eq(1, output.length);
+assert.eq(output[0].zipped, []);
+
+zipObj = {
+ inputs: [["$short"], ["$long"]]
+};
+res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
+output = res.toArray();
+assert.eq(1, output.length);
+assert.eq(output[0].zipped, [[['x', 'y'], [1, 2, 3]]]);
+
+zipObj = {
+ inputs: ["$short", "$long"]
+};
+res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
+output = res.toArray();
+assert.eq(1, output.length);
+assert.eq(output[0].zipped, [['x', 1], ['y', 2]]);
+
+zipObj = {
+ inputs: [["$long"]]
+};
+res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
+output = res.toArray();
+assert.eq(1, output.length);
+assert.eq(output[0].zipped, [[[1, 2, 3]]]);
+
+zipObj = {
+ inputs: [[1, 2, 3], ['a', 'b', 'c'], ['c', 'b', 'a']]
+};
+res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
+output = res.toArray();
+assert.eq(1, output.length);
+assert.eq(output[0].zipped, [[1, 'a', 'c'], [2, 'b', 'b'], [3, 'c', 'a']]);
+
+zipObj = {
+ inputs: [[1, 2, 3], ["A", "B"]],
+ defaults: ["C", "D"],
+ useLongestLength: true
+};
+res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
+output = res.toArray();
+assert.eq(1, output.length);
+assert.eq(output[0].zipped, [[1, "A"], [2, "B"], [3, "D"]]);
+
+zipObj = {
+ inputs: [[1, 2, 3], ["A", "B"]],
+ useLongestLength: true
+};
+res = coll.aggregate([{$project: {zipped: {$zip: zipObj}}}]);
+output = res.toArray();
+assert.eq(1, output.length);
+assert.eq(output[0].zipped, [[1, "A"], [2, "B"], [3, null]]);
}());
diff --git a/jstests/aggregation/bugs/server20168.js b/jstests/aggregation/bugs/server20168.js
index 2ff8c6e53cd..9a886bbc279 100644
--- a/jstests/aggregation/bugs/server20168.js
+++ b/jstests/aggregation/bugs/server20168.js
@@ -1,39 +1,38 @@
// SERVER-20168: Add option to $unwind to output a null result for empty arrays.
(function() {
- "use strict";
+"use strict";
- var coll = db.server20168;
- coll.drop();
+var coll = db.server20168;
+coll.drop();
- // Should return no results on a non-existent collection.
- var results = coll.aggregate([{$unwind: {path: "$x"}}]).toArray();
- assert.eq(0, results.length, "$unwind returned the wrong number of results");
+// Should return no results on a non-existent collection.
+var results = coll.aggregate([{$unwind: {path: "$x"}}]).toArray();
+assert.eq(0, results.length, "$unwind returned the wrong number of results");
- /**
- * Asserts that with the input 'inputDoc', an $unwind stage on 'unwindPath' should produce no
- * results if preserveNullAndEmptyArrays is not specified, and produces one result, equal to
- * 'outputDoc', if it is specified.
- */
- function testPreserveNullAndEmptyArraysParam(inputDoc, unwindPath, outputDoc) {
- coll.drop();
- assert.writeOK(coll.insert(inputDoc));
+/**
+ * Asserts that with the input 'inputDoc', an $unwind stage on 'unwindPath' should produce no
+ * results if preserveNullAndEmptyArrays is not specified, and produces one result, equal to
+ * 'outputDoc', if it is specified.
+ */
+function testPreserveNullAndEmptyArraysParam(inputDoc, unwindPath, outputDoc) {
+ coll.drop();
+ assert.writeOK(coll.insert(inputDoc));
- // If preserveNullAndEmptyArrays is passed, we should get an output document.
- var preservedResults =
- coll.aggregate([{$unwind: {path: unwindPath, preserveNullAndEmptyArrays: true}}])
- .toArray();
- assert.eq(1, preservedResults.length, "$unwind returned the wrong number of results");
- assert.eq(preservedResults[0],
- outputDoc,
- "Unexpected result for an $unwind with preserveNullAndEmptyArrays " +
- "(input was " + tojson(inputDoc) + ")");
+ // If preserveNullAndEmptyArrays is passed, we should get an output document.
+ var preservedResults =
+ coll.aggregate([{$unwind: {path: unwindPath, preserveNullAndEmptyArrays: true}}]).toArray();
+ assert.eq(1, preservedResults.length, "$unwind returned the wrong number of results");
+ assert.eq(preservedResults[0],
+ outputDoc,
+ "Unexpected result for an $unwind with preserveNullAndEmptyArrays " +
+ "(input was " + tojson(inputDoc) + ")");
- // If not, we should get no outputs.
- var defaultResults = coll.aggregate([{$unwind: {path: unwindPath}}]).toArray();
- assert.eq(0, defaultResults.length, "$unwind returned the wrong number of results");
- }
+ // If not, we should get no outputs.
+ var defaultResults = coll.aggregate([{$unwind: {path: unwindPath}}]).toArray();
+ assert.eq(0, defaultResults.length, "$unwind returned the wrong number of results");
+}
- testPreserveNullAndEmptyArraysParam({_id: 0}, "$x", {_id: 0});
- testPreserveNullAndEmptyArraysParam({_id: 0, x: null}, "$x", {_id: 0, x: null});
- testPreserveNullAndEmptyArraysParam({_id: 0, x: []}, "$x", {_id: 0});
+testPreserveNullAndEmptyArraysParam({_id: 0}, "$x", {_id: 0});
+testPreserveNullAndEmptyArraysParam({_id: 0, x: null}, "$x", {_id: 0, x: null});
+testPreserveNullAndEmptyArraysParam({_id: 0, x: []}, "$x", {_id: 0});
}());
diff --git a/jstests/aggregation/bugs/server20169.js b/jstests/aggregation/bugs/server20169.js
index 27995b8030c..2b5a969f803 100644
--- a/jstests/aggregation/bugs/server20169.js
+++ b/jstests/aggregation/bugs/server20169.js
@@ -3,59 +3,67 @@
load("jstests/aggregation/extras/utils.js"); // For assertErrorCode.
(function() {
- "use strict";
-
- var coll = db.range;
- coll.drop();
-
- // We need an input document to receive an output document.
- coll.insert({});
-
- var rangeObj = [1];
- assertErrorCode(coll,
- [{$project: {range: {$range: rangeObj}}}],
- 28667,
- "range requires two" + " or three arguments");
-
- rangeObj = ["a", 1];
- assertErrorCode(coll,
- [{$project: {range: {$range: rangeObj}}}],
- 34443,
- "range requires a" + " numeric starting value");
-
- rangeObj = [1.1, 1];
- assertErrorCode(coll,
- [{$project: {range: {$range: rangeObj}}}],
- 34444,
- "range requires an" + " integral starting value");
-
- rangeObj = [1, "a"];
- assertErrorCode(coll,
- [{$project: {range: {$range: rangeObj}}}],
- 34445,
- "range requires a" + " numeric ending value");
-
- rangeObj = [1, 1.1];
- assertErrorCode(coll,
- [{$project: {range: {$range: rangeObj}}}],
- 34446,
- "range requires an" + " integral ending value");
-
- rangeObj = [1, 3, "a"];
- assertErrorCode(coll,
- [{$project: {range: {$range: rangeObj}}}],
- 34447,
- "range requires a" + " numeric step value");
-
- rangeObj = [1, 3, 1.1];
- assertErrorCode(coll,
- [{$project: {range: {$range: rangeObj}}}],
- 34448,
- "range requires an" + " integral step value");
-
- rangeObj = [1, 3, 0];
- assertErrorCode(coll,
- [{$project: {range: {$range: rangeObj}}}],
- 34449,
- "range requires a" + " non-zero step value");
+"use strict";
+
+var coll = db.range;
+coll.drop();
+
+// We need an input document to receive an output document.
+coll.insert({});
+
+var rangeObj = [1];
+assertErrorCode(coll,
+ [{$project: {range: {$range: rangeObj}}}],
+ 28667,
+ "range requires two" +
+ " or three arguments");
+
+rangeObj = ["a", 1];
+assertErrorCode(coll,
+ [{$project: {range: {$range: rangeObj}}}],
+ 34443,
+ "range requires a" +
+ " numeric starting value");
+
+rangeObj = [1.1, 1];
+assertErrorCode(coll,
+ [{$project: {range: {$range: rangeObj}}}],
+ 34444,
+ "range requires an" +
+ " integral starting value");
+
+rangeObj = [1, "a"];
+assertErrorCode(coll,
+ [{$project: {range: {$range: rangeObj}}}],
+ 34445,
+ "range requires a" +
+ " numeric ending value");
+
+rangeObj = [1, 1.1];
+assertErrorCode(coll,
+ [{$project: {range: {$range: rangeObj}}}],
+ 34446,
+ "range requires an" +
+ " integral ending value");
+
+rangeObj = [1, 3, "a"];
+assertErrorCode(coll,
+ [{$project: {range: {$range: rangeObj}}}],
+ 34447,
+ "range requires a" +
+ " numeric step value");
+
+rangeObj = [1, 3, 1.1];
+assertErrorCode(coll,
+ [{$project: {range: {$range: rangeObj}}}],
+ 34448,
+ "range requires an" +
+ " integral step value");
+
+rangeObj = [1, 3, 0];
+assertErrorCode(coll,
+ [{$project: {range: {$range: rangeObj}}}],
+ 34449,
+ "range requires a" +
+ " non-zero step value");
}());
diff --git a/jstests/aggregation/bugs/server21632.js b/jstests/aggregation/bugs/server21632.js
index 944ca114ab6..c23d8836bea 100644
--- a/jstests/aggregation/bugs/server21632.js
+++ b/jstests/aggregation/bugs/server21632.js
@@ -11,77 +11,76 @@
// 2. We should not see any duplicate documents in any one $sample (this is only guaranteed if
// there are no ongoing write operations).
(function() {
- "use strict";
-
- var coll = db.server21632;
- coll.drop();
-
- // If there is no collection, or no documents in the collection, we should not get any results
- // from a sample.
- assert.eq([], coll.aggregate([{$sample: {size: 1}}]).toArray());
- assert.eq([], coll.aggregate([{$sample: {size: 10}}]).toArray());
-
- db.createCollection(coll.getName());
-
- // Test if we are running WT + LSM and if so, skip the test.
- // WiredTiger LSM random cursor implementation doesn't currently give random enough
- // distribution to pass this test case, so disable the test when checking an LSM
- // configuration for now. We will need revisit this before releasing WiredTiger LSM
- // as a supported file type. (See: WT-2403 for details on forthcoming changes)
-
- var storageEngine = jsTest.options().storageEngine || "wiredTiger";
-
- if (storageEngine == "wiredTiger" && coll.stats().wiredTiger.type == 'lsm') {
- return;
- }
-
- assert.eq([], coll.aggregate([{$sample: {size: 1}}]).toArray());
- assert.eq([], coll.aggregate([{$sample: {size: 10}}]).toArray());
-
- // If there is only one document, we should get that document.
- var paddingStr = "abcdefghijklmnopqrstuvwxyz";
- var firstDoc = {_id: 0, paddingStr: paddingStr};
- assert.writeOK(coll.insert(firstDoc));
- assert.eq([firstDoc], coll.aggregate([{$sample: {size: 1}}]).toArray());
- assert.eq([firstDoc], coll.aggregate([{$sample: {size: 10}}]).toArray());
-
- // Insert a bunch of documents.
- var bulk = coll.initializeUnorderedBulkOp();
- var nDocs = 1000;
- for (var id = 1; id < nDocs; id++) {
- bulk.insert({_id: id, paddingStr: paddingStr});
- }
- bulk.execute();
-
- // Will contain a document's _id as a key if we've ever seen that document.
- var cumulativeSeenIds = {};
- var sampleSize = 10;
-
- jsTestLog("About to do repeated samples, explain output: " +
- tojson(coll.explain().aggregate([{$sample: {size: sampleSize}}])));
-
- // Repeatedly ask for small samples of documents to get a cumulative sample of size 'nDocs'.
- for (var i = 0; i < nDocs / sampleSize; i++) {
- var results = coll.aggregate([{$sample: {size: sampleSize}}]).toArray();
-
- assert.eq(
- results.length, sampleSize, "$sample did not return the expected number of results");
-
- // Check that there are no duplicate documents in the result of any single sample.
- var idsThisSample = {};
- results.forEach(function recordId(result) {
- assert.lte(result._id, nDocs, "$sample returned an unknown document");
- assert(!idsThisSample[result._id],
- "A single $sample returned the same document twice: " + result._id);
-
- cumulativeSeenIds[result._id] = true;
- idsThisSample[result._id] = true;
- });
- }
-
- // An implementation would have to be very broken for this assertion to fail.
- assert.gte(Object.keys(cumulativeSeenIds).length, nDocs / 4);
-
- // Make sure we can return all documents in the collection.
- assert.eq(coll.aggregate([{$sample: {size: nDocs}}]).toArray().length, nDocs);
+"use strict";
+
+var coll = db.server21632;
+coll.drop();
+
+// If there is no collection, or no documents in the collection, we should not get any results
+// from a sample.
+assert.eq([], coll.aggregate([{$sample: {size: 1}}]).toArray());
+assert.eq([], coll.aggregate([{$sample: {size: 10}}]).toArray());
+
+db.createCollection(coll.getName());
+
+// Test if we are running WT + LSM and if so, skip the test.
+// WiredTiger LSM random cursor implementation doesn't currently give random enough
+// distribution to pass this test case, so disable the test when checking an LSM
+// configuration for now. We will need revisit this before releasing WiredTiger LSM
+// as a supported file type. (See: WT-2403 for details on forthcoming changes)
+
+var storageEngine = jsTest.options().storageEngine || "wiredTiger";
+
+if (storageEngine == "wiredTiger" && coll.stats().wiredTiger.type == 'lsm') {
+ return;
+}
+
+assert.eq([], coll.aggregate([{$sample: {size: 1}}]).toArray());
+assert.eq([], coll.aggregate([{$sample: {size: 10}}]).toArray());
+
+// If there is only one document, we should get that document.
+var paddingStr = "abcdefghijklmnopqrstuvwxyz";
+var firstDoc = {_id: 0, paddingStr: paddingStr};
+assert.writeOK(coll.insert(firstDoc));
+assert.eq([firstDoc], coll.aggregate([{$sample: {size: 1}}]).toArray());
+assert.eq([firstDoc], coll.aggregate([{$sample: {size: 10}}]).toArray());
+
+// Insert a bunch of documents.
+var bulk = coll.initializeUnorderedBulkOp();
+var nDocs = 1000;
+for (var id = 1; id < nDocs; id++) {
+ bulk.insert({_id: id, paddingStr: paddingStr});
+}
+bulk.execute();
+
+// Will contain a document's _id as a key if we've ever seen that document.
+var cumulativeSeenIds = {};
+var sampleSize = 10;
+
+jsTestLog("About to do repeated samples, explain output: " +
+ tojson(coll.explain().aggregate([{$sample: {size: sampleSize}}])));
+
+// Repeatedly ask for small samples of documents to get a cumulative sample of size 'nDocs'.
+for (var i = 0; i < nDocs / sampleSize; i++) {
+ var results = coll.aggregate([{$sample: {size: sampleSize}}]).toArray();
+
+ assert.eq(results.length, sampleSize, "$sample did not return the expected number of results");
+
+ // Check that there are no duplicate documents in the result of any single sample.
+ var idsThisSample = {};
+ results.forEach(function recordId(result) {
+ assert.lte(result._id, nDocs, "$sample returned an unknown document");
+ assert(!idsThisSample[result._id],
+ "A single $sample returned the same document twice: " + result._id);
+
+ cumulativeSeenIds[result._id] = true;
+ idsThisSample[result._id] = true;
+ });
+}
+
+// An implementation would have to be very broken for this assertion to fail.
+assert.gte(Object.keys(cumulativeSeenIds).length, nDocs / 4);
+
+// Make sure we can return all documents in the collection.
+assert.eq(coll.aggregate([{$sample: {size: nDocs}}]).toArray().length, nDocs);
})();
diff --git a/jstests/aggregation/bugs/server22093.js b/jstests/aggregation/bugs/server22093.js
index 61068e38493..618c65f85b7 100644
--- a/jstests/aggregation/bugs/server22093.js
+++ b/jstests/aggregation/bugs/server22093.js
@@ -11,42 +11,42 @@
load('jstests/libs/analyze_plan.js');
(function() {
- "use strict";
+"use strict";
- var coll = db.countscan;
- coll.drop();
+var coll = db.countscan;
+coll.drop();
- for (var i = 0; i < 3; i++) {
- for (var j = 0; j < 10; j += 2) {
- coll.insert({foo: i, bar: j});
- }
+for (var i = 0; i < 3; i++) {
+ for (var j = 0; j < 10; j += 2) {
+ coll.insert({foo: i, bar: j});
}
+}
- coll.ensureIndex({foo: 1});
+coll.ensureIndex({foo: 1});
- var simpleGroup = coll.aggregate([{$group: {_id: null, count: {$sum: 1}}}]).toArray();
+var simpleGroup = coll.aggregate([{$group: {_id: null, count: {$sum: 1}}}]).toArray();
- assert.eq(simpleGroup.length, 1);
- assert.eq(simpleGroup[0]["count"], 15);
+assert.eq(simpleGroup.length, 1);
+assert.eq(simpleGroup[0]["count"], 15);
- var explained = coll.explain().aggregate(
- [{$match: {foo: {$gt: 0}}}, {$group: {_id: null, count: {$sum: 1}}}]);
+var explained =
+ coll.explain().aggregate([{$match: {foo: {$gt: 0}}}, {$group: {_id: null, count: {$sum: 1}}}]);
- assert(planHasStage(db, explained.stages[0].$cursor.queryPlanner.winningPlan, "COUNT_SCAN"));
+assert(planHasStage(db, explained.stages[0].$cursor.queryPlanner.winningPlan, "COUNT_SCAN"));
- explained = coll.explain().aggregate([
- {$match: {foo: {$gt: 0}}},
- {$project: {_id: 0, a: {$literal: null}}},
- {$group: {_id: null, count: {$sum: 1}}}
- ]);
+explained = coll.explain().aggregate([
+ {$match: {foo: {$gt: 0}}},
+ {$project: {_id: 0, a: {$literal: null}}},
+ {$group: {_id: null, count: {$sum: 1}}}
+]);
- assert(planHasStage(db, explained.stages[0].$cursor.queryPlanner.winningPlan, "COUNT_SCAN"));
+assert(planHasStage(db, explained.stages[0].$cursor.queryPlanner.winningPlan, "COUNT_SCAN"));
- // Make sure a $count stage can use the COUNT_SCAN optimization.
- explained = coll.explain().aggregate([{$match: {foo: {$gt: 0}}}, {$count: "count"}]);
- assert(planHasStage(db, explained.stages[0].$cursor.queryPlanner.winningPlan, "COUNT_SCAN"));
+// Make sure a $count stage can use the COUNT_SCAN optimization.
+explained = coll.explain().aggregate([{$match: {foo: {$gt: 0}}}, {$count: "count"}]);
+assert(planHasStage(db, explained.stages[0].$cursor.queryPlanner.winningPlan, "COUNT_SCAN"));
- // A $match that is not a single range cannot use the COUNT_SCAN optimization.
- explained = coll.explain().aggregate([{$match: {foo: {$in: [0, 1]}}}, {$count: "count"}]);
- assert(!planHasStage(db, explained.stages[0].$cursor.queryPlanner.winningPlan, "COUNT_SCAN"));
+// A $match that is not a single range cannot use the COUNT_SCAN optimization.
+explained = coll.explain().aggregate([{$match: {foo: {$in: [0, 1]}}}, {$count: "count"}]);
+assert(!planHasStage(db, explained.stages[0].$cursor.queryPlanner.winningPlan, "COUNT_SCAN"));
}());
diff --git a/jstests/aggregation/bugs/server22580.js b/jstests/aggregation/bugs/server22580.js
index 3a448173875..3b9f81dbcfc 100644
--- a/jstests/aggregation/bugs/server22580.js
+++ b/jstests/aggregation/bugs/server22580.js
@@ -3,41 +3,46 @@
load("jstests/aggregation/extras/utils.js"); // For assertErrorCode.
(function() {
- "use strict";
-
- var coll = db.substrCP;
- coll.drop();
-
- // Need an empty document for pipeline.
- coll.insert({});
-
- assertErrorCode(coll,
- [{$project: {substr: {$substrCP: ["abc", 0, "a"]}}}],
- 34452,
- "$substrCP" + " does not accept non-numeric types as a length.");
-
- assertErrorCode(coll,
- [{$project: {substr: {$substrCP: ["abc", 0, NaN]}}}],
- 34453,
- "$substrCP" + " does not accept non-integers as a length.");
-
- assertErrorCode(coll,
- [{$project: {substr: {$substrCP: ["abc", "abc", 3]}}}],
- 34450,
- "$substrCP does not accept non-numeric types as a starting index.");
-
- assertErrorCode(coll,
- [{$project: {substr: {$substrCP: ["abc", 2.2, 3]}}}],
- 34451,
- "$substrCP" + " does not accept non-integers as a starting index.");
-
- assertErrorCode(coll,
- [{$project: {substr: {$substrCP: ["abc", -1, 3]}}}],
- 34455,
- "$substrCP " + "does not accept negative integers as inputs.");
-
- assertErrorCode(coll,
- [{$project: {substr: {$substrCP: ["abc", 1, -3]}}}],
- 34454,
- "$substrCP " + "does not accept negative integers as inputs.");
+"use strict";
+
+var coll = db.substrCP;
+coll.drop();
+
+// Need an empty document for pipeline.
+coll.insert({});
+
+assertErrorCode(coll,
+ [{$project: {substr: {$substrCP: ["abc", 0, "a"]}}}],
+ 34452,
+ "$substrCP" +
+ " does not accept non-numeric types as a length.");
+
+assertErrorCode(coll,
+ [{$project: {substr: {$substrCP: ["abc", 0, NaN]}}}],
+ 34453,
+ "$substrCP" +
+ " does not accept non-integers as a length.");
+
+assertErrorCode(coll,
+ [{$project: {substr: {$substrCP: ["abc", "abc", 3]}}}],
+ 34450,
+ "$substrCP does not accept non-numeric types as a starting index.");
+
+assertErrorCode(coll,
+ [{$project: {substr: {$substrCP: ["abc", 2.2, 3]}}}],
+ 34451,
+ "$substrCP" +
+ " does not accept non-integers as a starting index.");
+
+assertErrorCode(coll,
+ [{$project: {substr: {$substrCP: ["abc", -1, 3]}}}],
+ 34455,
+ "$substrCP " +
+ "does not accept negative integers as inputs.");
+
+assertErrorCode(coll,
+ [{$project: {substr: {$substrCP: ["abc", 1, -3]}}}],
+ 34454,
+ "$substrCP " +
+ "does not accept negative integers as inputs.");
}());
diff --git a/jstests/aggregation/bugs/server25590.js b/jstests/aggregation/bugs/server25590.js
index 329ae808a2c..b478f806029 100644
--- a/jstests/aggregation/bugs/server25590.js
+++ b/jstests/aggregation/bugs/server25590.js
@@ -1,19 +1,19 @@
// Test that an aggregate command where the "pipeline" field has the wrong type fails with a
// TypeMismatch error.
(function() {
- "use strict";
+"use strict";
- const coll = db.server25590;
- coll.drop();
+const coll = db.server25590;
+coll.drop();
- assert.writeOK(coll.insert({}));
+assert.writeOK(coll.insert({}));
- assert.commandFailedWithCode(db.runCommand({aggregate: coll.getName(), pipeline: 1}),
- ErrorCodes.TypeMismatch);
- assert.commandFailedWithCode(db.runCommand({aggregate: coll.getName(), pipeline: {}}),
- ErrorCodes.TypeMismatch);
- assert.commandFailedWithCode(db.runCommand({aggregate: coll.getName(), pipeline: [1, 2]}),
- ErrorCodes.TypeMismatch);
- assert.commandFailedWithCode(db.runCommand({aggregate: coll.getName(), pipeline: [1, null]}),
- ErrorCodes.TypeMismatch);
+assert.commandFailedWithCode(db.runCommand({aggregate: coll.getName(), pipeline: 1}),
+ ErrorCodes.TypeMismatch);
+assert.commandFailedWithCode(db.runCommand({aggregate: coll.getName(), pipeline: {}}),
+ ErrorCodes.TypeMismatch);
+assert.commandFailedWithCode(db.runCommand({aggregate: coll.getName(), pipeline: [1, 2]}),
+ ErrorCodes.TypeMismatch);
+assert.commandFailedWithCode(db.runCommand({aggregate: coll.getName(), pipeline: [1, null]}),
+ ErrorCodes.TypeMismatch);
})();
diff --git a/jstests/aggregation/bugs/server26462.js b/jstests/aggregation/bugs/server26462.js
index b0ef33ae35b..08225e54ce3 100644
--- a/jstests/aggregation/bugs/server26462.js
+++ b/jstests/aggregation/bugs/server26462.js
@@ -1,29 +1,29 @@
// Tests that adding a field that only contains metadata does not cause a segmentation fault when
// grouping on the added field.
(function() {
- "use strict";
+"use strict";
- // Drop the old test collection, if any.
- db.server26462.drop();
+// Drop the old test collection, if any.
+db.server26462.drop();
- // Insert some test documents into the collection.
- assert.writeOK(db.server26462.insert({"_id": 1, "title": "cakes and ale"}));
- assert.writeOK(db.server26462.insert({"_id": 2, "title": "more cakes"}));
- assert.writeOK(db.server26462.insert({"_id": 3, "title": "bread"}));
- assert.writeOK(db.server26462.insert({"_id": 4, "title": "some cakes"}));
+// Insert some test documents into the collection.
+assert.writeOK(db.server26462.insert({"_id": 1, "title": "cakes and ale"}));
+assert.writeOK(db.server26462.insert({"_id": 2, "title": "more cakes"}));
+assert.writeOK(db.server26462.insert({"_id": 3, "title": "bread"}));
+assert.writeOK(db.server26462.insert({"_id": 4, "title": "some cakes"}));
- // Create a text index on the documents.
- assert.commandWorked(db.server26462.createIndex({title: "text"}));
+// Create a text index on the documents.
+assert.commandWorked(db.server26462.createIndex({title: "text"}));
- // Add a metadata only field in the aggregation pipeline and use that field in the $group _id.
- let res = db.server26462
- .aggregate([
- {$match: {$text: {$search: "cake"}}},
- {$addFields: {fooScore: {$meta: "textScore"}}},
- {$group: {_id: "$fooScore", count: {$sum: 1}}}
- ])
- .itcount();
+// Add a metadata only field in the aggregation pipeline and use that field in the $group _id.
+let res = db.server26462
+ .aggregate([
+ {$match: {$text: {$search: "cake"}}},
+ {$addFields: {fooScore: {$meta: "textScore"}}},
+ {$group: {_id: "$fooScore", count: {$sum: 1}}}
+ ])
+ .itcount();
- // Assert that the command worked.
- assert.eq(2, res);
+// Assert that the command worked.
+assert.eq(2, res);
})();
diff --git a/jstests/aggregation/bugs/server37750.js b/jstests/aggregation/bugs/server37750.js
index cdfd098d87d..902c427c292 100644
--- a/jstests/aggregation/bugs/server37750.js
+++ b/jstests/aggregation/bugs/server37750.js
@@ -6,75 +6,75 @@
* requires_sharding]
*/
(function() {
- "use strict";
+"use strict";
- load("jstests/libs/fixture_helpers.js"); // For FixtureHelpers.
+load("jstests/libs/fixture_helpers.js"); // For FixtureHelpers.
- // Set up a 2-shard cluster. Configure 'internalQueryExecYieldIterations' on both shards such
- // that operations will yield on each PlanExecuter iteration.
- const st = new ShardingTest({
- name: jsTestName(),
- shards: 2,
- rs: {nodes: 1, setParameter: {internalQueryExecYieldIterations: 1}}
- });
+// Set up a 2-shard cluster. Configure 'internalQueryExecYieldIterations' on both shards such
+// that operations will yield on each PlanExecuter iteration.
+const st = new ShardingTest({
+ name: jsTestName(),
+ shards: 2,
+ rs: {nodes: 1, setParameter: {internalQueryExecYieldIterations: 1}}
+});
- const mongosDB = st.s.getDB(jsTestName());
- const mongosColl = mongosDB.test;
+const mongosDB = st.s.getDB(jsTestName());
+const mongosColl = mongosDB.test;
- // Shard the test collection, split it at {_id: 0}, and move the upper chunk to shard1.
- st.shardColl(mongosColl, {_id: 1}, {_id: 0}, {_id: 0});
+// Shard the test collection, split it at {_id: 0}, and move the upper chunk to shard1.
+st.shardColl(mongosColl, {_id: 1}, {_id: 0}, {_id: 0});
- // Insert enough documents on each shard to induce the $sample random-cursor optimization.
- for (let i = (-150); i < 150; ++i) {
- assert.commandWorked(mongosColl.insert({_id: i}));
- }
+// Insert enough documents on each shard to induce the $sample random-cursor optimization.
+for (let i = (-150); i < 150; ++i) {
+ assert.commandWorked(mongosColl.insert({_id: i}));
+}
- // Run the initial aggregate for the $sample stage.
- const cmdRes = assert.commandWorked(mongosDB.runCommand({
- aggregate: mongosColl.getName(),
- pipeline: [{$sample: {size: 3}}],
- comment: "$sample random",
- cursor: {batchSize: 0}
- }));
- assert.eq(cmdRes.cursor.firstBatch.length, 0);
+// Run the initial aggregate for the $sample stage.
+const cmdRes = assert.commandWorked(mongosDB.runCommand({
+ aggregate: mongosColl.getName(),
+ pipeline: [{$sample: {size: 3}}],
+ comment: "$sample random",
+ cursor: {batchSize: 0}
+}));
+assert.eq(cmdRes.cursor.firstBatch.length, 0);
- // Force each shard to hang on yield to allow for currentOp capture.
- FixtureHelpers.runCommandOnEachPrimary({
- db: mongosDB.getSiblingDB("admin"),
- cmdObj: {
- configureFailPoint: "setYieldAllLocksHang",
- mode: "alwaysOn",
- data: {namespace: mongosColl.getFullName()}
- }
- });
+// Force each shard to hang on yield to allow for currentOp capture.
+FixtureHelpers.runCommandOnEachPrimary({
+ db: mongosDB.getSiblingDB("admin"),
+ cmdObj: {
+ configureFailPoint: "setYieldAllLocksHang",
+ mode: "alwaysOn",
+ data: {namespace: mongosColl.getFullName()}
+ }
+});
- // Run $currentOp to confirm that the $sample getMore yields on both shards.
- const awaitShell = startParallelShell(() => {
- load("jstests/libs/fixture_helpers.js");
- assert.soon(() => db.getSiblingDB("admin")
- .aggregate([
- {$currentOp: {}},
- {
- $match: {
- "cursor.originatingCommand.comment": "$sample random",
- planSummary: "QUEUED_DATA, MULTI_ITERATOR",
- numYields: {$gt: 0}
- }
+// Run $currentOp to confirm that the $sample getMore yields on both shards.
+const awaitShell = startParallelShell(() => {
+ load("jstests/libs/fixture_helpers.js");
+ assert.soon(() => db.getSiblingDB("admin")
+ .aggregate([
+ {$currentOp: {}},
+ {
+ $match: {
+ "cursor.originatingCommand.comment": "$sample random",
+ planSummary: "QUEUED_DATA, MULTI_ITERATOR",
+ numYields: {$gt: 0}
}
- ])
- .itcount() === 2);
- // Release the failpoint and allow the getMores to complete.
- FixtureHelpers.runCommandOnEachPrimary({
- db: db.getSiblingDB("admin"),
- cmdObj: {configureFailPoint: "setYieldAllLocksHang", mode: "off"}
- });
- }, mongosDB.getMongo().port);
+ }
+ ])
+ .itcount() === 2);
+ // Release the failpoint and allow the getMores to complete.
+ FixtureHelpers.runCommandOnEachPrimary({
+ db: db.getSiblingDB("admin"),
+ cmdObj: {configureFailPoint: "setYieldAllLocksHang", mode: "off"}
+ });
+}, mongosDB.getMongo().port);
- // Retrieve the results for the $sample aggregation.
- const sampleCursor = new DBCommandCursor(mongosDB, cmdRes);
- assert.eq(sampleCursor.toArray().length, 3);
+// Retrieve the results for the $sample aggregation.
+const sampleCursor = new DBCommandCursor(mongosDB, cmdRes);
+assert.eq(sampleCursor.toArray().length, 3);
- // Confirm that the parallel shell completes successfully, and tear down the cluster.
- awaitShell();
- st.stop();
+// Confirm that the parallel shell completes successfully, and tear down the cluster.
+awaitShell();
+st.stop();
})(); \ No newline at end of file
diff --git a/jstests/aggregation/bugs/server4588.js b/jstests/aggregation/bugs/server4588.js
index 000cc8f0231..be04773c0ff 100644
--- a/jstests/aggregation/bugs/server4588.js
+++ b/jstests/aggregation/bugs/server4588.js
@@ -1,60 +1,55 @@
// SERVER-4588 Add option to $unwind to emit array index.
(function() {
- "use strict";
+"use strict";
- const coll = db.server4588;
- coll.drop();
+const coll = db.server4588;
+coll.drop();
- assert.writeOK(coll.insert({_id: 0}));
- assert.writeOK(coll.insert({_id: 1, x: null}));
- assert.writeOK(coll.insert({_id: 2, x: []}));
- assert.writeOK(coll.insert({_id: 3, x: [1, 2, 3]}));
- assert.writeOK(coll.insert({_id: 4, x: 5}));
+assert.writeOK(coll.insert({_id: 0}));
+assert.writeOK(coll.insert({_id: 1, x: null}));
+assert.writeOK(coll.insert({_id: 2, x: []}));
+assert.writeOK(coll.insert({_id: 3, x: [1, 2, 3]}));
+assert.writeOK(coll.insert({_id: 4, x: 5}));
- // Without includeArrayIndex.
- 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},
- {_id: 4, x: 5},
- ];
- assert.eq(expectedResults, actualResults, "Incorrect results for normal $unwind");
+// Without includeArrayIndex.
+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},
+ {_id: 4, x: 5},
+];
+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"}}, {$sort: {_id: 1, x: 1}}])
- .toArray();
- expectedResults = [
- {_id: 3, x: 1, index: NumberLong(0)},
- {_id: 3, x: 2, index: NumberLong(1)},
- {_id: 3, x: 3, index: NumberLong(2)},
- {_id: 4, x: 5, index: null},
- ];
- assert.eq(expectedResults, actualResults, "Incorrect results $unwind with includeArrayIndex");
+// With includeArrayIndex, index inserted into a new field.
+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)},
+ {_id: 3, x: 3, index: NumberLong(2)},
+ {_id: 4, x: 5, index: null},
+];
+assert.eq(expectedResults, actualResults, "Incorrect results $unwind with includeArrayIndex");
- // With both includeArrayIndex and preserveNullAndEmptyArrays.
- actualResults =
- coll.aggregate([
- {
- $unwind:
- {path: "$x", includeArrayIndex: "index", preserveNullAndEmptyArrays: true}
- },
- {$sort: {_id: 1, x: 1}}
- ])
- .toArray();
- expectedResults = [
- {_id: 0, index: null},
- {_id: 1, x: null, index: null},
- {_id: 2, index: null},
- {_id: 3, x: 1, index: NumberLong(0)},
- {_id: 3, x: 2, index: NumberLong(1)},
- {_id: 3, x: 3, index: NumberLong(2)},
- {_id: 4, x: 5, index: null},
- ];
- assert.eq(expectedResults,
- actualResults,
- "Incorrect results $unwind with includeArrayIndex and preserveNullAndEmptyArrays");
+// With both includeArrayIndex and preserveNullAndEmptyArrays.
+actualResults =
+ coll.aggregate([
+ {$unwind: {path: "$x", includeArrayIndex: "index", preserveNullAndEmptyArrays: true}},
+ {$sort: {_id: 1, x: 1}}
+ ])
+ .toArray();
+expectedResults = [
+ {_id: 0, index: null},
+ {_id: 1, x: null, index: null},
+ {_id: 2, index: null},
+ {_id: 3, x: 1, index: NumberLong(0)},
+ {_id: 3, x: 2, index: NumberLong(1)},
+ {_id: 3, x: 3, index: NumberLong(2)},
+ {_id: 4, x: 5, index: null},
+];
+assert.eq(expectedResults,
+ actualResults,
+ "Incorrect results $unwind with includeArrayIndex and preserveNullAndEmptyArrays");
}());
diff --git a/jstests/aggregation/bugs/server4589.js b/jstests/aggregation/bugs/server4589.js
index e7f2e1b9746..efa7254e4d9 100644
--- a/jstests/aggregation/bugs/server4589.js
+++ b/jstests/aggregation/bugs/server4589.js
@@ -4,67 +4,67 @@
load('jstests/aggregation/extras/utils.js');
(function() {
- 'use strict';
-
- var coll = db.agg_array_elem_at_expr;
- coll.drop();
-
- assert.writeOK(coll.insert({a: [1, 2, 3, 4, 5]}));
-
- // Normal indexing.
- var pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', 2]}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{x: 3}]);
-
- // Indexing with a float.
- pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', 1.0]}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{x: 2}]);
-
- // Indexing with a decimal
- pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', NumberDecimal('2.0')]}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{x: 3}]);
-
- // Negative indexing.
- pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', -1]}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{x: 5}]);
- pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', -5]}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{x: 1}]);
-
- // Out of bounds positive.
- pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', 5]}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{}]);
- pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', Math.pow(2, 31) - 1]}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{}]);
- pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', NumberLong(Math.pow(2, 31) - 1)]}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{}]);
-
- // Out of bounds negative.
- pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', -6]}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{}]);
- pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', -Math.pow(2, 31)]}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{}]);
- pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', NumberLong(-Math.pow(2, 31))]}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{}]);
-
- // Null inputs.
- pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', null]}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{x: null}]);
- pipeline = [{$project: {_id: 0, x: {$arrayElemAt: [null, 4]}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{x: null}]);
-
- // Error cases.
-
- // Wrong number of arguments.
- assertErrorCode(coll, [{$project: {x: {$arrayElemAt: [['one', 'arg']]}}}], 16020);
-
- // First argument is not an array.
- assertErrorCode(coll, [{$project: {x: {$arrayElemAt: ['one', 2]}}}], 28689);
-
- // Second argument is not numeric.
- assertErrorCode(coll, [{$project: {x: {$arrayElemAt: [[1, 2], '2']}}}], 28690);
-
- // Second argument is not integral.
- assertErrorCode(coll, [{$project: {x: {$arrayElemAt: [[1, 2], 1.5]}}}], 28691);
- assertErrorCode(coll, [{$project: {x: {$arrayElemAt: [[1, 2], NumberDecimal('1.5')]}}}], 28691);
- assertErrorCode(coll, [{$project: {x: {$arrayElemAt: [[1, 2], Math.pow(2, 32)]}}}], 28691);
- assertErrorCode(coll, [{$project: {x: {$arrayElemAt: [[1, 2], -Math.pow(2, 31) - 1]}}}], 28691);
+'use strict';
+
+var coll = db.agg_array_elem_at_expr;
+coll.drop();
+
+assert.writeOK(coll.insert({a: [1, 2, 3, 4, 5]}));
+
+// Normal indexing.
+var pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', 2]}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{x: 3}]);
+
+// Indexing with a float.
+pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', 1.0]}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{x: 2}]);
+
+// Indexing with a decimal
+pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', NumberDecimal('2.0')]}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{x: 3}]);
+
+// Negative indexing.
+pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', -1]}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{x: 5}]);
+pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', -5]}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{x: 1}]);
+
+// Out of bounds positive.
+pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', 5]}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{}]);
+pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', Math.pow(2, 31) - 1]}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{}]);
+pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', NumberLong(Math.pow(2, 31) - 1)]}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{}]);
+
+// Out of bounds negative.
+pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', -6]}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{}]);
+pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', -Math.pow(2, 31)]}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{}]);
+pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', NumberLong(-Math.pow(2, 31))]}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{}]);
+
+// Null inputs.
+pipeline = [{$project: {_id: 0, x: {$arrayElemAt: ['$a', null]}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{x: null}]);
+pipeline = [{$project: {_id: 0, x: {$arrayElemAt: [null, 4]}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{x: null}]);
+
+// Error cases.
+
+// Wrong number of arguments.
+assertErrorCode(coll, [{$project: {x: {$arrayElemAt: [['one', 'arg']]}}}], 16020);
+
+// First argument is not an array.
+assertErrorCode(coll, [{$project: {x: {$arrayElemAt: ['one', 2]}}}], 28689);
+
+// Second argument is not numeric.
+assertErrorCode(coll, [{$project: {x: {$arrayElemAt: [[1, 2], '2']}}}], 28690);
+
+// Second argument is not integral.
+assertErrorCode(coll, [{$project: {x: {$arrayElemAt: [[1, 2], 1.5]}}}], 28691);
+assertErrorCode(coll, [{$project: {x: {$arrayElemAt: [[1, 2], NumberDecimal('1.5')]}}}], 28691);
+assertErrorCode(coll, [{$project: {x: {$arrayElemAt: [[1, 2], Math.pow(2, 32)]}}}], 28691);
+assertErrorCode(coll, [{$project: {x: {$arrayElemAt: [[1, 2], -Math.pow(2, 31) - 1]}}}], 28691);
}());
diff --git a/jstests/aggregation/bugs/server4638.js b/jstests/aggregation/bugs/server4638.js
index 4934da94a34..ee6f7cfd6df 100644
--- a/jstests/aggregation/bugs/server4638.js
+++ b/jstests/aggregation/bugs/server4638.js
@@ -13,4 +13,4 @@ assert.eq(res[0].x, 0);
// Make sure having an undefined doesn't break pipelines that do use the field
res = t.aggregate({$project: {undef: 1}}).toArray();
assert.eq(res[0].undef, undefined);
-assert.eq(typeof(res[0].undef), "undefined");
+assert.eq(typeof (res[0].undef), "undefined");
diff --git a/jstests/aggregation/bugs/server5012.js b/jstests/aggregation/bugs/server5012.js
index a9955349490..14dfe914b52 100644
--- a/jstests/aggregation/bugs/server5012.js
+++ b/jstests/aggregation/bugs/server5012.js
@@ -1,11 +1,11 @@
(function() {
- "use strict";
- load('jstests/aggregation/data/articles.js');
+"use strict";
+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"}];
+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"}];
- assert.eq(cursor.toArray(), expected);
+assert.eq(cursor.toArray(), expected);
}());
diff --git a/jstests/aggregation/bugs/server533.js b/jstests/aggregation/bugs/server533.js
index b64ddc9669f..d66c5d27ad8 100644
--- a/jstests/aggregation/bugs/server533.js
+++ b/jstests/aggregation/bugs/server533.js
@@ -4,32 +4,32 @@
load('jstests/aggregation/extras/utils.js');
(function() {
- 'use strict';
-
- var coll = db.agg_sample;
- coll.drop();
-
- // Should return no results on a collection that doesn't exist. Should not crash.
- assert.eq(coll.aggregate([{$sample: {size: 10}}]).toArray(), []);
-
- var nItems = 3;
- for (var i = 0; i < nItems; i++) {
- assert.writeOK(coll.insert({_id: i}));
- }
-
- [0, 1, nItems, nItems + 1].forEach(function(size) {
- var results = coll.aggregate([{$sample: {size: size}}]).toArray();
- assert.eq(results.length, Math.min(size, nItems));
- });
-
- // Multiple $sample stages are allowed.
- var results = coll.aggregate([{$sample: {size: nItems}}, {$sample: {size: 1}}]).toArray();
- assert.eq(results.length, 1);
-
- // Invalid options.
- assertErrorCode(coll, [{$sample: 'string'}], 28745);
- assertErrorCode(coll, [{$sample: {size: 'string'}}], 28746);
- assertErrorCode(coll, [{$sample: {size: -1}}], 28747);
- assertErrorCode(coll, [{$sample: {unknownOpt: true}}], 28748);
- assertErrorCode(coll, [{$sample: {/* no size */}}], 28749);
+'use strict';
+
+var coll = db.agg_sample;
+coll.drop();
+
+// Should return no results on a collection that doesn't exist. Should not crash.
+assert.eq(coll.aggregate([{$sample: {size: 10}}]).toArray(), []);
+
+var nItems = 3;
+for (var i = 0; i < nItems; i++) {
+ assert.writeOK(coll.insert({_id: i}));
+}
+
+[0, 1, nItems, nItems + 1].forEach(function(size) {
+ var results = coll.aggregate([{$sample: {size: size}}]).toArray();
+ assert.eq(results.length, Math.min(size, nItems));
+});
+
+// Multiple $sample stages are allowed.
+var results = coll.aggregate([{$sample: {size: nItems}}, {$sample: {size: 1}}]).toArray();
+assert.eq(results.length, 1);
+
+// Invalid options.
+assertErrorCode(coll, [{$sample: 'string'}], 28745);
+assertErrorCode(coll, [{$sample: {size: 'string'}}], 28746);
+assertErrorCode(coll, [{$sample: {size: -1}}], 28747);
+assertErrorCode(coll, [{$sample: {unknownOpt: true}}], 28748);
+assertErrorCode(coll, [{$sample: {/* no size */}}], 28749);
}());
diff --git a/jstests/aggregation/bugs/server6074.js b/jstests/aggregation/bugs/server6074.js
index 8adf6b7eca8..8e53459ba9e 100644
--- a/jstests/aggregation/bugs/server6074.js
+++ b/jstests/aggregation/bugs/server6074.js
@@ -4,78 +4,78 @@
load('jstests/aggregation/extras/utils.js');
(function() {
- 'use strict';
-
- var coll = db.agg_slice_expr;
- coll.drop();
-
- // Need to have at least one document to ensure the pipeline executes.
- assert.writeOK(coll.insert({}));
-
- function testSlice(sliceArgs, expArray) {
- var pipeline = [{$project: {_id: 0, slice: {$slice: sliceArgs}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{slice: expArray}]);
- }
-
- // Two argument form.
-
- testSlice([[0, 1, 2, 3, 4], 2], [0, 1]);
- testSlice([[0, 1, 2, 3, 4], 2.0], [0, 1]);
- // Negative count
- testSlice([[0, 1, 2, 3, 4], -2], [3, 4]);
- testSlice([[0, 1, 2, 3, 4], -2.0], [3, 4]);
- // Zero count.
- testSlice([[0, 1, 2, 3, 4], 0], []);
- // Out of bounds positive.
- testSlice([[0, 1, 2, 3, 4], 10], [0, 1, 2, 3, 4]);
- // Out of bounds negative.
- testSlice([[0, 1, 2, 3, 4], -10], [0, 1, 2, 3, 4]);
- // Null arguments
- testSlice([null, -10], null);
- testSlice([[0, 1, 2, 3, 4], null], null);
-
- // Three argument form.
-
- testSlice([[0, 1, 2, 3, 4], 1, 2], [1, 2]);
- testSlice([[0, 1, 2, 3, 4], 1.0, 2.0], [1, 2]);
- // Negative start index.
- testSlice([[0, 1, 2, 3, 4], -3, 2], [2, 3]);
- testSlice([[0, 1, 2, 3, 4], -5, 2], [0, 1]);
- // Slice starts out of bounds.
- testSlice([[0, 1, 2, 3, 4], -10, 2], [0, 1]);
- testSlice([[0, 1, 2, 3, 4], 10, 2], []);
- // Slice ends out of bounds.
- testSlice([[0, 1, 2, 3, 4], 4, 3], [4]);
- testSlice([[0, 1, 2, 3, 4], -1, 3], [4]);
- // Null arguments
- testSlice([[0, 1, 2, 3, 4], -1, null], null);
-
- // Error cases.
-
- // Wrong number of arguments.
- assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2, 3]]}}}], 28667);
- assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2, 3], 4, 5, 6]}}}], 28667);
-
- // First argument is not an array.
- assertErrorCode(coll, [{$project: {x: {$slice: ['one', 2]}}}], 28724);
-
- // Second argument is not numeric.
- assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2], '2']}}}], 28725);
-
- // Second argument is not integral.
- assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2], 1.5]}}}], 28726);
- assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2], Math.pow(2, 32)]}}}], 28726);
- assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2], -Math.pow(2, 31) - 1]}}}], 28726);
-
- // Third argument is not numeric.
- assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2], 0, '2']}}}], 28727);
-
- // Third argument is not integral.
- assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2], 0, 1.5]}}}], 28728);
- assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2], 0, Math.pow(2, 32)]}}}], 28728);
- assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2], 0, -Math.pow(2, 31) - 1]}}}], 28728);
-
- // Third argument is not positive.
- assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2], 0, 0]}}}], 28729);
- assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2], 0, -1]}}}], 28729);
+'use strict';
+
+var coll = db.agg_slice_expr;
+coll.drop();
+
+// Need to have at least one document to ensure the pipeline executes.
+assert.writeOK(coll.insert({}));
+
+function testSlice(sliceArgs, expArray) {
+ var pipeline = [{$project: {_id: 0, slice: {$slice: sliceArgs}}}];
+ assert.eq(coll.aggregate(pipeline).toArray(), [{slice: expArray}]);
+}
+
+// Two argument form.
+
+testSlice([[0, 1, 2, 3, 4], 2], [0, 1]);
+testSlice([[0, 1, 2, 3, 4], 2.0], [0, 1]);
+// Negative count
+testSlice([[0, 1, 2, 3, 4], -2], [3, 4]);
+testSlice([[0, 1, 2, 3, 4], -2.0], [3, 4]);
+// Zero count.
+testSlice([[0, 1, 2, 3, 4], 0], []);
+// Out of bounds positive.
+testSlice([[0, 1, 2, 3, 4], 10], [0, 1, 2, 3, 4]);
+// Out of bounds negative.
+testSlice([[0, 1, 2, 3, 4], -10], [0, 1, 2, 3, 4]);
+// Null arguments
+testSlice([null, -10], null);
+testSlice([[0, 1, 2, 3, 4], null], null);
+
+// Three argument form.
+
+testSlice([[0, 1, 2, 3, 4], 1, 2], [1, 2]);
+testSlice([[0, 1, 2, 3, 4], 1.0, 2.0], [1, 2]);
+// Negative start index.
+testSlice([[0, 1, 2, 3, 4], -3, 2], [2, 3]);
+testSlice([[0, 1, 2, 3, 4], -5, 2], [0, 1]);
+// Slice starts out of bounds.
+testSlice([[0, 1, 2, 3, 4], -10, 2], [0, 1]);
+testSlice([[0, 1, 2, 3, 4], 10, 2], []);
+// Slice ends out of bounds.
+testSlice([[0, 1, 2, 3, 4], 4, 3], [4]);
+testSlice([[0, 1, 2, 3, 4], -1, 3], [4]);
+// Null arguments
+testSlice([[0, 1, 2, 3, 4], -1, null], null);
+
+// Error cases.
+
+// Wrong number of arguments.
+assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2, 3]]}}}], 28667);
+assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2, 3], 4, 5, 6]}}}], 28667);
+
+// First argument is not an array.
+assertErrorCode(coll, [{$project: {x: {$slice: ['one', 2]}}}], 28724);
+
+// Second argument is not numeric.
+assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2], '2']}}}], 28725);
+
+// Second argument is not integral.
+assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2], 1.5]}}}], 28726);
+assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2], Math.pow(2, 32)]}}}], 28726);
+assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2], -Math.pow(2, 31) - 1]}}}], 28726);
+
+// Third argument is not numeric.
+assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2], 0, '2']}}}], 28727);
+
+// Third argument is not integral.
+assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2], 0, 1.5]}}}], 28728);
+assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2], 0, Math.pow(2, 32)]}}}], 28728);
+assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2], 0, -Math.pow(2, 31) - 1]}}}], 28728);
+
+// Third argument is not positive.
+assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2], 0, 0]}}}], 28729);
+assertErrorCode(coll, [{$project: {x: {$slice: [[1, 2], 0, -1]}}}], 28729);
}());
diff --git a/jstests/aggregation/bugs/server6125.js b/jstests/aggregation/bugs/server6125.js
index 592a560312a..bd4ab4ce220 100644
--- a/jstests/aggregation/bugs/server6125.js
+++ b/jstests/aggregation/bugs/server6125.js
@@ -65,9 +65,9 @@ function setupArray() {
{_id: 13, a: new Timestamp(1 / 1000, 1), ty: "Timestamp"},
{_id: 14, a: /regex/, ty: "RegExp"},
{
- _id: 15,
- a: new DBPointer("test.s6125", new ObjectId("0102030405060708090A0B0C")),
- ty: "DBPointer"
+ _id: 15,
+ a: new DBPointer("test.s6125", new ObjectId("0102030405060708090A0B0C")),
+ ty: "DBPointer"
},
{_id: 16, a: function() {}, ty: "Code"},
// Code with Scope not implemented in JS
diff --git a/jstests/aggregation/bugs/server6127.js b/jstests/aggregation/bugs/server6127.js
index 26585c87d21..1f11d858c83 100644
--- a/jstests/aggregation/bugs/server6127.js
+++ b/jstests/aggregation/bugs/server6127.js
@@ -7,21 +7,21 @@
* is no path). Previous it would uassert causing the aggregation to end.
*/
(function() {
- "use strict";
- db.s6127.drop();
+"use strict";
+db.s6127.drop();
- 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}}));
+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"}}]);
+// 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"}}]);
- // 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);
+// 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 0969b366636..c74e1848512 100644
--- a/jstests/aggregation/bugs/server6147.js
+++ b/jstests/aggregation/bugs/server6147.js
@@ -6,44 +6,44 @@
* constant and a field regardless of whether they were equal or not.
*/
(function() {
- "use strict";
- db.s6147.drop();
+"use strict";
+db.s6147.drop();
- assert.writeOK(db.s6147.insert({a: 1}));
- assert.writeOK(db.s6147.insert({a: 2}));
+assert.writeOK(db.s6147.insert({a: 1}));
+assert.writeOK(db.s6147.insert({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.
+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"]}
}
- ]);
+ }
+]);
- // 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
- }
- ];
+// 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.eq(cursor.toArray(), expected);
+assert.eq(cursor.toArray(), expected);
}());
diff --git a/jstests/aggregation/bugs/server6179.js b/jstests/aggregation/bugs/server6179.js
index a5e934a9e89..065f5b261ee 100644
--- a/jstests/aggregation/bugs/server6179.js
+++ b/jstests/aggregation/bugs/server6179.js
@@ -4,53 +4,53 @@
// requires_spawning_own_processes,
// ]
(function() {
- 'use strict';
-
- var s = new ShardingTest({shards: 2});
-
- assert.commandWorked(s.s0.adminCommand({enablesharding: "test"}));
- s.ensurePrimaryShard('test', s.shard1.shardName);
- assert.commandWorked(s.s0.adminCommand({shardcollection: "test.data", key: {_id: 1}}));
-
- var d = s.getDB("test");
-
- // Insert _id values 0 - 99
- var N = 100;
-
- var bulkOp = d.data.initializeOrderedBulkOp();
- for (var i = 0; i < N; ++i) {
- bulkOp.insert({_id: i, i: i % 10});
- }
- bulkOp.execute();
-
- // Split the data into 3 chunks
- assert.commandWorked(s.s0.adminCommand({split: "test.data", middle: {_id: 33}}));
- assert.commandWorked(s.s0.adminCommand({split: "test.data", middle: {_id: 66}}));
-
- // Migrate the middle chunk to another shard
- assert.commandWorked(s.s0.adminCommand(
- {movechunk: "test.data", find: {_id: 50}, to: s.getOther(s.getPrimaryShard("test")).name}));
-
- // Check that we get results rather than an error
- var result = d.data
- .aggregate({$group: {_id: '$_id', i: {$first: '$i'}}},
- {$group: {_id: '$i', avg_id: {$avg: '$_id'}}},
- {$sort: {_id: 1}})
- .toArray();
- var expected = [
- {"_id": 0, "avg_id": 45},
- {"_id": 1, "avg_id": 46},
- {"_id": 2, "avg_id": 47},
- {"_id": 3, "avg_id": 48},
- {"_id": 4, "avg_id": 49},
- {"_id": 5, "avg_id": 50},
- {"_id": 6, "avg_id": 51},
- {"_id": 7, "avg_id": 52},
- {"_id": 8, "avg_id": 53},
- {"_id": 9, "avg_id": 54}
- ];
-
- assert.eq(result, expected);
-
- s.stop();
+'use strict';
+
+var s = new ShardingTest({shards: 2});
+
+assert.commandWorked(s.s0.adminCommand({enablesharding: "test"}));
+s.ensurePrimaryShard('test', s.shard1.shardName);
+assert.commandWorked(s.s0.adminCommand({shardcollection: "test.data", key: {_id: 1}}));
+
+var d = s.getDB("test");
+
+// Insert _id values 0 - 99
+var N = 100;
+
+var bulkOp = d.data.initializeOrderedBulkOp();
+for (var i = 0; i < N; ++i) {
+ bulkOp.insert({_id: i, i: i % 10});
+}
+bulkOp.execute();
+
+// Split the data into 3 chunks
+assert.commandWorked(s.s0.adminCommand({split: "test.data", middle: {_id: 33}}));
+assert.commandWorked(s.s0.adminCommand({split: "test.data", middle: {_id: 66}}));
+
+// Migrate the middle chunk to another shard
+assert.commandWorked(s.s0.adminCommand(
+ {movechunk: "test.data", find: {_id: 50}, to: s.getOther(s.getPrimaryShard("test")).name}));
+
+// Check that we get results rather than an error
+var result = d.data
+ .aggregate({$group: {_id: '$_id', i: {$first: '$i'}}},
+ {$group: {_id: '$i', avg_id: {$avg: '$_id'}}},
+ {$sort: {_id: 1}})
+ .toArray();
+var expected = [
+ {"_id": 0, "avg_id": 45},
+ {"_id": 1, "avg_id": 46},
+ {"_id": 2, "avg_id": 47},
+ {"_id": 3, "avg_id": 48},
+ {"_id": 4, "avg_id": 49},
+ {"_id": 5, "avg_id": 50},
+ {"_id": 6, "avg_id": 51},
+ {"_id": 7, "avg_id": 52},
+ {"_id": 8, "avg_id": 53},
+ {"_id": 9, "avg_id": 54}
+];
+
+assert.eq(result, expected);
+
+s.stop();
})();
diff --git a/jstests/aggregation/bugs/server6185.js b/jstests/aggregation/bugs/server6185.js
index cf084d4b371..06eacdf791d 100644
--- a/jstests/aggregation/bugs/server6185.js
+++ b/jstests/aggregation/bugs/server6185.js
@@ -2,16 +2,16 @@
* Tests that projecting a non-existent subfield behaves identically in both query and aggregation.
*/
(function() {
- "use strict";
- const coll = db.c;
- coll.drop();
+"use strict";
+const coll = db.c;
+coll.drop();
- 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.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.eq(coll.aggregate([{$project: {'a.b': 1}}, {$sort: {_id: 1}}]).toArray(),
- coll.find({}, {'a.b': 1}).sort({_id: 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/server6530.js b/jstests/aggregation/bugs/server6530.js
index 36a5d3deb3f..77dfcd703fb 100644
--- a/jstests/aggregation/bugs/server6530.js
+++ b/jstests/aggregation/bugs/server6530.js
@@ -2,31 +2,37 @@
* Test that $near queries are disallowed in $match stages.
*/
(function() {
- "use strict";
- load("jstests/aggregation/extras/utils.js");
+"use strict";
+load("jstests/aggregation/extras/utils.js");
- const coll = db.getCollection("no_near_in_match");
- coll.drop();
+const coll = db.getCollection("no_near_in_match");
+coll.drop();
- // Create indexes that could satisfy various $near queries.
- assert.commandWorked(coll.createIndex({point2d: "2d"}));
- assert.commandWorked(coll.createIndex({point2dsphere: "2dsphere"}));
+// Create indexes that could satisfy various $near queries.
+assert.commandWorked(coll.createIndex({point2d: "2d"}));
+assert.commandWorked(coll.createIndex({point2dsphere: "2dsphere"}));
- // Populate the collection so that successful queries can return at least one result.
- assert.writeOK(coll.insert({point2d: [0.25, 0.35]}));
- assert.writeOK(coll.insert({point2dsphere: [0.25, 0.35]}));
+// Populate the collection so that successful queries can return at least one result.
+assert.writeOK(coll.insert({point2d: [0.25, 0.35]}));
+assert.writeOK(coll.insert({point2dsphere: [0.25, 0.35]}));
- const nearQuery = {point2d: {$near: [0, 0]}};
- const nearSphereQuery = {point2dsphere: {$nearSphere: [0, 0]}};
- const geoNearQuery = {point2d: {$geoNear: [0, 0]}};
+const nearQuery = {
+ point2d: {$near: [0, 0]}
+};
+const nearSphereQuery = {
+ point2dsphere: {$nearSphere: [0, 0]}
+};
+const geoNearQuery = {
+ point2d: {$geoNear: [0, 0]}
+};
- // Test that normal finds return a result.
- assert.eq(1, coll.find(nearQuery).count());
- assert.eq(1, coll.find(nearSphereQuery).count());
- assert.eq(1, coll.find(geoNearQuery).count());
+// Test that normal finds return a result.
+assert.eq(1, coll.find(nearQuery).count());
+assert.eq(1, coll.find(nearSphereQuery).count());
+assert.eq(1, coll.find(geoNearQuery).count());
- // Test that we refuse to run $match with a near query.
- assertErrorCode(coll, {$match: nearQuery}, ErrorCodes.BadValue);
- assertErrorCode(coll, {$match: nearSphereQuery}, ErrorCodes.BadValue);
- assertErrorCode(coll, {$match: geoNearQuery}, ErrorCodes.BadValue);
+// Test that we refuse to run $match with a near query.
+assertErrorCode(coll, {$match: nearQuery}, ErrorCodes.BadValue);
+assertErrorCode(coll, {$match: nearSphereQuery}, ErrorCodes.BadValue);
+assertErrorCode(coll, {$match: geoNearQuery}, ErrorCodes.BadValue);
}());
diff --git a/jstests/aggregation/bugs/server6779.js b/jstests/aggregation/bugs/server6779.js
index 44f641ea15d..d9d48898068 100644
--- a/jstests/aggregation/bugs/server6779.js
+++ b/jstests/aggregation/bugs/server6779.js
@@ -1,20 +1,20 @@
// server 6779: serializing ExpressionCoerceToBool
// This test only fails in debug mode with the bug since that tests round-tripping
(function() {
- "use strict";
+"use strict";
- function test(op, val) {
- const coll = db.server6779;
- coll.drop();
- assert.writeOK(coll.insert({a: true}));
- assert.writeOK(coll.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}));
- const obj = {};
- obj[op] = ['$a', val];
- const result = coll.aggregate([{$project: {_id: 0, bool: obj}}, {$sort: {bool: -1}}]);
+ 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/server7695_isodates.js b/jstests/aggregation/bugs/server7695_isodates.js
index 4d969bf80f8..ca90c47f0fe 100644
--- a/jstests/aggregation/bugs/server7695_isodates.js
+++ b/jstests/aggregation/bugs/server7695_isodates.js
@@ -1,254 +1,251 @@
// SERVER-7695: Add $isoWeek, $isoWeekYear, and $isoDayOfWeek aggregation expressions.
(function() {
- "use strict";
- const coll = db.server7695;
- let testOpCount = 0;
-
- load('jstests/libs/dateutil.js');
-
- coll.drop();
-
- // Seed collection so that the pipeline will execute.
- assert.writeOK(coll.insert({}));
-
- /**
- * Helper for testing that 'op' returns 'expResult'.
- */
- function testOp(op, value, expResult) {
- testOpCount++;
- let pipeline = [{$project: {_id: 0, result: {}}}];
- pipeline[0].$project.result[op] = value;
- let msg = "Exptected {" + op + ": " + value + "} to equal: " + expResult;
- let res = coll.runCommand('aggregate', {pipeline: pipeline, cursor: {}});
-
- // in the case of $dateToString the date is on property date
- let date = value.date || value;
- if (date.valueOf() < 0 && _isWindows() && res.code === 16422) {
- // some versions of windows (but not all) fail with dates before 1970
- print("skipping test of " + date.tojson() +
- " because system doesn't support old dates");
- return;
- }
-
- if (date.valueOf() / 1000 < -2 * 1024 * 1024 * 1024 && res.code == 16421) {
- // we correctly detected that we are outside of the range of a 32-bit time_t
- print("skipping test of " + date.tojson() + " because it is outside of time_t range");
- return;
- }
+"use strict";
+const coll = db.server7695;
+let testOpCount = 0;
+
+load('jstests/libs/dateutil.js');
+
+coll.drop();
+
+// Seed collection so that the pipeline will execute.
+assert.writeOK(coll.insert({}));
+
+/**
+ * Helper for testing that 'op' returns 'expResult'.
+ */
+function testOp(op, value, expResult) {
+ testOpCount++;
+ let pipeline = [{$project: {_id: 0, result: {}}}];
+ pipeline[0].$project.result[op] = value;
+ let msg = "Exptected {" + op + ": " + value + "} to equal: " + expResult;
+ let res = coll.runCommand('aggregate', {pipeline: pipeline, cursor: {}});
+
+ // in the case of $dateToString the date is on property date
+ let date = value.date || value;
+ if (date.valueOf() < 0 && _isWindows() && res.code === 16422) {
+ // some versions of windows (but not all) fail with dates before 1970
+ print("skipping test of " + date.tojson() + " because system doesn't support old dates");
+ return;
+ }
- assert.eq(res.cursor.firstBatch[0].result, expResult, tojson(pipeline));
+ if (date.valueOf() / 1000 < -2 * 1024 * 1024 * 1024 && res.code == 16421) {
+ // we correctly detected that we are outside of the range of a 32-bit time_t
+ print("skipping test of " + date.tojson() + " because it is outside of time_t range");
+ return;
}
- // While development, there was a bug which caused an error with $dateToString if the order of
- // %V and %G changed, so I added this test to prevent regression.
- testOp('$dateToString', {date: new Date("1900-12-31T23:59:59Z"), format: "%V-%G"}, "01-1901");
- // This was failing, but it shouldn't as it is the same as above, only rotated.
- testOp('$dateToString', {date: new Date("1900-12-31T23:59:59Z"), format: "%G-%V"}, "1901-01");
-
- // 1900 is special because it's devisible by 4 and by 100 but not 400 so it's not a leap year.
- // 2000 is special, because it's devisible by 4, 100, 400 and so it is a leap year.
- const years = {
- common: [
- 1900, // Starting and ending on Monday (special).
- 2002, // Starting and ending on Tuesday.
- 2014, // Starting and ending on Wednesday.
- 2015, // Starting and ending on Thursday.
- 2010, // Starting and ending on Friday.
- 2011, // Starting and ending on Saturday.
- 2006, // Starting and ending on Sunday.
- ],
- leap: [
- 1996, // Starting on Monday, ending on Tuesday.
- 2008, // Starting on Tuesday, ending on Wednesday.
- 1992, // Starting on Wednesday, ending on Thursday.
- 2004, // Starting on Thursday, ending on Friday.
- 2016, // Starting on Friday, ending on Saturday.
- 2000, // Starting on Saturday, ending on Sunday (special).
- 2012, // Starting on Sunday, ending on Monday.
- ],
- commonAfterLeap: [
- 2001, // Starting and ending on Monday.
- 2013, // Starting and ending on Tuesday.
- 1997, // Starting and ending on Wednesday.
- 2009, // Starting and ending on Thursday.
- 1993, // Starting and ending on Friday.
- 2005, // Starting and ending on Saturday.
- 2017, // Starting and ending on Sunday.
- ],
- };
-
- const MONDAY = 1;
- const TUESDAY = 2;
- const WEDNESDAY = 3;
- const THURSDAY = 4;
- const FRIDAY = 5;
- const SATURDAY = 6;
- const SUNDAY = 7;
-
- ['common', 'leap', 'commonAfterLeap'].forEach(function(type) {
- years[type].forEach(function(year, day) {
- // forEach starts indexing at zero but weekdays start with Monday on 1 so we add +1.
- day = day + 1;
- let newYear = DateUtil.getNewYear(year);
- let endOfFirstWeekInYear = DateUtil.getEndOfFirstWeekInYear(year, day);
- let startOfSecondWeekInYear = DateUtil.getStartOfSecondWeekInYear(year, day);
- let birthday = DateUtil.getBirthday(year);
- let endOfSecondToLastWeekInYear =
- DateUtil.getEndOfSecondToLastWeekInYear(year, day, type);
- let startOfLastWeekInYear = DateUtil.getStartOfLastWeekInYear(year, day, type);
- let newYearsEve = DateUtil.getNewYearsEve(year);
-
- testOp('$isoDayOfWeek', newYear, day);
- testOp('$isoDayOfWeek', endOfFirstWeekInYear, SUNDAY);
- testOp('$isoDayOfWeek', startOfSecondWeekInYear, MONDAY);
- testOp('$isoDayOfWeek', endOfSecondToLastWeekInYear, SUNDAY);
- testOp('$isoDayOfWeek', startOfLastWeekInYear, MONDAY);
- if (type === 'leap') {
- testOp('$isoDayOfWeek', newYearsEve, DateUtil.shiftWeekday(day, 1));
- } else {
- testOp('$isoDayOfWeek', newYearsEve, day);
- }
+ assert.eq(res.cursor.firstBatch[0].result, expResult, tojson(pipeline));
+}
+
+// While development, there was a bug which caused an error with $dateToString if the order of
+// %V and %G changed, so I added this test to prevent regression.
+testOp('$dateToString', {date: new Date("1900-12-31T23:59:59Z"), format: "%V-%G"}, "01-1901");
+// This was failing, but it shouldn't as it is the same as above, only rotated.
+testOp('$dateToString', {date: new Date("1900-12-31T23:59:59Z"), format: "%G-%V"}, "1901-01");
+
+// 1900 is special because it's devisible by 4 and by 100 but not 400 so it's not a leap year.
+// 2000 is special, because it's devisible by 4, 100, 400 and so it is a leap year.
+const years = {
+ common: [
+ 1900, // Starting and ending on Monday (special).
+ 2002, // Starting and ending on Tuesday.
+ 2014, // Starting and ending on Wednesday.
+ 2015, // Starting and ending on Thursday.
+ 2010, // Starting and ending on Friday.
+ 2011, // Starting and ending on Saturday.
+ 2006, // Starting and ending on Sunday.
+ ],
+ leap: [
+ 1996, // Starting on Monday, ending on Tuesday.
+ 2008, // Starting on Tuesday, ending on Wednesday.
+ 1992, // Starting on Wednesday, ending on Thursday.
+ 2004, // Starting on Thursday, ending on Friday.
+ 2016, // Starting on Friday, ending on Saturday.
+ 2000, // Starting on Saturday, ending on Sunday (special).
+ 2012, // Starting on Sunday, ending on Monday.
+ ],
+ commonAfterLeap: [
+ 2001, // Starting and ending on Monday.
+ 2013, // Starting and ending on Tuesday.
+ 1997, // Starting and ending on Wednesday.
+ 2009, // Starting and ending on Thursday.
+ 1993, // Starting and ending on Friday.
+ 2005, // Starting and ending on Saturday.
+ 2017, // Starting and ending on Sunday.
+ ],
+};
+
+const MONDAY = 1;
+const TUESDAY = 2;
+const WEDNESDAY = 3;
+const THURSDAY = 4;
+const FRIDAY = 5;
+const SATURDAY = 6;
+const SUNDAY = 7;
+
+['common', 'leap', 'commonAfterLeap'].forEach(function(type) {
+ years[type].forEach(function(year, day) {
+ // forEach starts indexing at zero but weekdays start with Monday on 1 so we add +1.
+ day = day + 1;
+ let newYear = DateUtil.getNewYear(year);
+ let endOfFirstWeekInYear = DateUtil.getEndOfFirstWeekInYear(year, day);
+ let startOfSecondWeekInYear = DateUtil.getStartOfSecondWeekInYear(year, day);
+ let birthday = DateUtil.getBirthday(year);
+ let endOfSecondToLastWeekInYear = DateUtil.getEndOfSecondToLastWeekInYear(year, day, type);
+ let startOfLastWeekInYear = DateUtil.getStartOfLastWeekInYear(year, day, type);
+ let newYearsEve = DateUtil.getNewYearsEve(year);
+
+ testOp('$isoDayOfWeek', newYear, day);
+ testOp('$isoDayOfWeek', endOfFirstWeekInYear, SUNDAY);
+ testOp('$isoDayOfWeek', startOfSecondWeekInYear, MONDAY);
+ testOp('$isoDayOfWeek', endOfSecondToLastWeekInYear, SUNDAY);
+ testOp('$isoDayOfWeek', startOfLastWeekInYear, MONDAY);
+ if (type === 'leap') {
+ testOp('$isoDayOfWeek', newYearsEve, DateUtil.shiftWeekday(day, 1));
+ } else {
+ testOp('$isoDayOfWeek', newYearsEve, day);
+ }
- if (type === 'leap') {
- testOp('$isoDayOfWeek', birthday, DateUtil.shiftWeekday(day, 4));
- } else {
- testOp('$isoDayOfWeek', birthday, DateUtil.shiftWeekday(day, 3));
- }
+ if (type === 'leap') {
+ testOp('$isoDayOfWeek', birthday, DateUtil.shiftWeekday(day, 4));
+ } else {
+ testOp('$isoDayOfWeek', birthday, DateUtil.shiftWeekday(day, 3));
+ }
- testOp('$isoWeekYear', birthday, year);
- // In leap years staring on Thursday, the birthday is in week 28, every year else it is
- // in week 27.
- if (type === 'leap' && day === THURSDAY) {
- testOp('$isoWeek', birthday, 28);
- } else {
- testOp('$isoWeek', birthday, 27);
- }
+ testOp('$isoWeekYear', birthday, year);
+ // In leap years staring on Thursday, the birthday is in week 28, every year else it is
+ // in week 27.
+ if (type === 'leap' && day === THURSDAY) {
+ testOp('$isoWeek', birthday, 28);
+ } else {
+ testOp('$isoWeek', birthday, 27);
+ }
- if (day <= THURSDAY) {
- // A year starting between Monday and Thursday will always start in week 1.
- testOp('$isoWeek', newYear, 1);
- testOp('$isoWeekYear', newYear, year);
- testOp('$isoWeek', endOfFirstWeekInYear, 1);
- testOp('$isoWeekYear', endOfFirstWeekInYear, year);
- testOp('$isoWeek', startOfSecondWeekInYear, 2);
- testOp('$isoWeekYear', startOfSecondWeekInYear, year);
+ if (day <= THURSDAY) {
+ // A year starting between Monday and Thursday will always start in week 1.
+ testOp('$isoWeek', newYear, 1);
+ testOp('$isoWeekYear', newYear, year);
+ testOp('$isoWeek', endOfFirstWeekInYear, 1);
+ testOp('$isoWeekYear', endOfFirstWeekInYear, year);
+ testOp('$isoWeek', startOfSecondWeekInYear, 2);
+ testOp('$isoWeekYear', startOfSecondWeekInYear, year);
+ testOp(
+ '$dateToString', {format: '%G-W%V-%u', date: newYear}, "" + year + "-W01-" + day);
+ } else if (day == FRIDAY || (day == SATURDAY && type === 'commonAfterLeap')) {
+ // A year starting on Friday will always start with week 53 of the previous year.
+ // A common year starting on a Saturday and after a leap year will also start with
+ // week 53 of the previous year.
+ testOp('$isoWeek', newYear, 53);
+ testOp('$isoWeekYear', newYear, year - 1);
+ testOp('$isoWeek', endOfFirstWeekInYear, 53);
+ testOp('$isoWeekYear', endOfFirstWeekInYear, year - 1);
+ testOp('$isoWeek', startOfSecondWeekInYear, 1);
+ testOp('$isoWeekYear', startOfSecondWeekInYear, year);
+ testOp('$dateToString',
+ {format: '%G-W%V-%u', date: newYear},
+ "" + (year - 1) + "-W53-" + day);
+ } else {
+ // A year starting on Saturday (except after a leap year) or Sunday will always
+ // start with week 52 of the previous year.
+ testOp('$isoWeek', newYear, 52);
+ testOp('$isoWeekYear', newYear, year - 1);
+ testOp('$isoWeek', endOfFirstWeekInYear, 52);
+ testOp('$isoWeekYear', endOfFirstWeekInYear, year - 1);
+ testOp('$isoWeek', startOfSecondWeekInYear, 1);
+ testOp('$isoWeekYear', startOfSecondWeekInYear, year);
+ testOp('$dateToString',
+ {format: '%G-W%V-%u', date: newYear},
+ "" + (year - 1) + "-W52-" + day);
+ }
+
+ if (type === 'leap') {
+ if (day <= TUESDAY) {
+ // A leap year starting between Monday and Tuesday will always end in week 1 of
+ // the next year.
+ testOp('$isoWeek', newYearsEve, 1);
+ testOp('$isoWeekYear', newYearsEve, year + 1);
+ testOp('$isoWeek', endOfSecondToLastWeekInYear, 52);
+ testOp('$isoWeekYear', endOfSecondToLastWeekInYear, year);
+ testOp('$isoWeek', startOfLastWeekInYear, 1);
+ testOp('$isoWeekYear', startOfLastWeekInYear, year + 1);
+ testOp('$dateToString',
+ {format: '%G-W%V-%u', date: newYearsEve},
+ "" + (year + 1) + "-W01-" + DateUtil.shiftWeekday(day, 1));
+ } else if (day <= THURSDAY) {
+ // A leap year starting on Wednesday or Thursday will always end with week 53.
+ testOp('$isoWeek', newYearsEve, 53);
+ testOp('$isoWeekYear', newYearsEve, year);
+ testOp('$isoWeek', endOfSecondToLastWeekInYear, 52);
+ testOp('$isoWeekYear', endOfSecondToLastWeekInYear, year);
+ testOp('$isoWeek', startOfLastWeekInYear, 53);
+ testOp('$isoWeekYear', startOfLastWeekInYear, year);
testOp('$dateToString',
- {format: '%G-W%V-%u', date: newYear},
- "" + year + "-W01-" + day);
- } else if (day == FRIDAY || (day == SATURDAY && type === 'commonAfterLeap')) {
- // A year starting on Friday will always start with week 53 of the previous year.
- // A common year starting on a Saturday and after a leap year will also start with
- // week 53 of the previous year.
- testOp('$isoWeek', newYear, 53);
- testOp('$isoWeekYear', newYear, year - 1);
- testOp('$isoWeek', endOfFirstWeekInYear, 53);
- testOp('$isoWeekYear', endOfFirstWeekInYear, year - 1);
- testOp('$isoWeek', startOfSecondWeekInYear, 1);
- testOp('$isoWeekYear', startOfSecondWeekInYear, year);
+ {format: '%G-W%V-%u', date: newYearsEve},
+ "" + (year) + "-W53-" + DateUtil.shiftWeekday(day, 1));
+ } else if (day <= SATURDAY) {
+ // A leap year starting on Friday or Sarturday will always and with week 52
+ testOp('$isoWeek', newYearsEve, 52);
+ testOp('$isoWeekYear', newYearsEve, year);
+ testOp('$isoWeek', endOfSecondToLastWeekInYear, 51);
+ testOp('$isoWeekYear', endOfSecondToLastWeekInYear, year);
+ testOp('$isoWeek', startOfLastWeekInYear, 52);
+ testOp('$isoWeekYear', startOfLastWeekInYear, year);
testOp('$dateToString',
- {format: '%G-W%V-%u', date: newYear},
- "" + (year - 1) + "-W53-" + day);
+ {format: '%G-W%V-%u', date: newYearsEve},
+ "" + (year) + "-W52-" + DateUtil.shiftWeekday(day, 1));
} else {
- // A year starting on Saturday (except after a leap year) or Sunday will always
- // start with week 52 of the previous year.
- testOp('$isoWeek', newYear, 52);
- testOp('$isoWeekYear', newYear, year - 1);
- testOp('$isoWeek', endOfFirstWeekInYear, 52);
- testOp('$isoWeekYear', endOfFirstWeekInYear, year - 1);
- testOp('$isoWeek', startOfSecondWeekInYear, 1);
- testOp('$isoWeekYear', startOfSecondWeekInYear, year);
+ // A leap year starting on Sunday will always end with week 1
+ testOp('$isoWeek', newYearsEve, 1);
+ testOp('$isoWeekYear', newYearsEve, year + 1);
+ testOp('$isoWeek', endOfSecondToLastWeekInYear, 51);
+ testOp('$isoWeekYear', endOfSecondToLastWeekInYear, year);
+ testOp('$isoWeek', startOfLastWeekInYear, 52);
+ testOp('$isoWeekYear', startOfLastWeekInYear, year);
testOp('$dateToString',
- {format: '%G-W%V-%u', date: newYear},
- "" + (year - 1) + "-W52-" + day);
+ {format: '%G-W%V-%u', date: newYearsEve},
+ "" + (year + 1) + "-W01-" + DateUtil.shiftWeekday(day, 1));
}
-
- if (type === 'leap') {
- if (day <= TUESDAY) {
- // A leap year starting between Monday and Tuesday will always end in week 1 of
- // the next year.
- testOp('$isoWeek', newYearsEve, 1);
- testOp('$isoWeekYear', newYearsEve, year + 1);
- testOp('$isoWeek', endOfSecondToLastWeekInYear, 52);
- testOp('$isoWeekYear', endOfSecondToLastWeekInYear, year);
- testOp('$isoWeek', startOfLastWeekInYear, 1);
- testOp('$isoWeekYear', startOfLastWeekInYear, year + 1);
- testOp('$dateToString',
- {format: '%G-W%V-%u', date: newYearsEve},
- "" + (year + 1) + "-W01-" + DateUtil.shiftWeekday(day, 1));
- } else if (day <= THURSDAY) {
- // A leap year starting on Wednesday or Thursday will always end with week 53.
- testOp('$isoWeek', newYearsEve, 53);
- testOp('$isoWeekYear', newYearsEve, year);
- testOp('$isoWeek', endOfSecondToLastWeekInYear, 52);
- testOp('$isoWeekYear', endOfSecondToLastWeekInYear, year);
- testOp('$isoWeek', startOfLastWeekInYear, 53);
- testOp('$isoWeekYear', startOfLastWeekInYear, year);
- testOp('$dateToString',
- {format: '%G-W%V-%u', date: newYearsEve},
- "" + (year) + "-W53-" + DateUtil.shiftWeekday(day, 1));
- } else if (day <= SATURDAY) {
- // A leap year starting on Friday or Sarturday will always and with week 52
- testOp('$isoWeek', newYearsEve, 52);
- testOp('$isoWeekYear', newYearsEve, year);
- testOp('$isoWeek', endOfSecondToLastWeekInYear, 51);
- testOp('$isoWeekYear', endOfSecondToLastWeekInYear, year);
- testOp('$isoWeek', startOfLastWeekInYear, 52);
- testOp('$isoWeekYear', startOfLastWeekInYear, year);
- testOp('$dateToString',
- {format: '%G-W%V-%u', date: newYearsEve},
- "" + (year) + "-W52-" + DateUtil.shiftWeekday(day, 1));
- } else {
- // A leap year starting on Sunday will always end with week 1
- testOp('$isoWeek', newYearsEve, 1);
- testOp('$isoWeekYear', newYearsEve, year + 1);
- testOp('$isoWeek', endOfSecondToLastWeekInYear, 51);
- testOp('$isoWeekYear', endOfSecondToLastWeekInYear, year);
- testOp('$isoWeek', startOfLastWeekInYear, 52);
- testOp('$isoWeekYear', startOfLastWeekInYear, year);
- testOp('$dateToString',
- {format: '%G-W%V-%u', date: newYearsEve},
- "" + (year + 1) + "-W01-" + DateUtil.shiftWeekday(day, 1));
- }
+ } else {
+ if (day <= WEDNESDAY) {
+ // A common year starting between Monday and Wednesday will always end in week 1
+ // of the next year.
+ testOp('$isoWeek', newYearsEve, 1);
+ testOp('$isoWeekYear', newYearsEve, year + 1);
+ testOp('$isoWeek', endOfSecondToLastWeekInYear, 52);
+ testOp('$isoWeekYear', endOfSecondToLastWeekInYear, year);
+ testOp('$isoWeek', startOfLastWeekInYear, 1);
+ testOp('$isoWeekYear', startOfLastWeekInYear, year + 1);
+ testOp('$dateToString',
+ {format: '%G-W%V-%u', date: newYearsEve},
+ "" + (year + 1) + "-W01-" + day);
+ } else if (day === THURSDAY) {
+ // A common year starting on Thursday will always end with week 53.
+ testOp('$isoWeek', newYearsEve, 53);
+ testOp('$isoWeekYear', newYearsEve, year);
+ testOp('$isoWeek', endOfSecondToLastWeekInYear, 52);
+ testOp('$isoWeekYear', endOfSecondToLastWeekInYear, year);
+ testOp('$isoWeek', startOfLastWeekInYear, 53);
+ testOp('$isoWeekYear', startOfLastWeekInYear, year);
+ testOp('$dateToString',
+ {format: '%G-W%V-%u', date: newYearsEve},
+ "" + (year) + "-W53-" + day);
} else {
- if (day <= WEDNESDAY) {
- // A common year starting between Monday and Wednesday will always end in week 1
- // of the next year.
- testOp('$isoWeek', newYearsEve, 1);
- testOp('$isoWeekYear', newYearsEve, year + 1);
- testOp('$isoWeek', endOfSecondToLastWeekInYear, 52);
- testOp('$isoWeekYear', endOfSecondToLastWeekInYear, year);
- testOp('$isoWeek', startOfLastWeekInYear, 1);
- testOp('$isoWeekYear', startOfLastWeekInYear, year + 1);
- testOp('$dateToString',
- {format: '%G-W%V-%u', date: newYearsEve},
- "" + (year + 1) + "-W01-" + day);
- } else if (day === THURSDAY) {
- // A common year starting on Thursday will always end with week 53.
- testOp('$isoWeek', newYearsEve, 53);
- testOp('$isoWeekYear', newYearsEve, year);
- testOp('$isoWeek', endOfSecondToLastWeekInYear, 52);
- testOp('$isoWeekYear', endOfSecondToLastWeekInYear, year);
- testOp('$isoWeek', startOfLastWeekInYear, 53);
- testOp('$isoWeekYear', startOfLastWeekInYear, year);
- testOp('$dateToString',
- {format: '%G-W%V-%u', date: newYearsEve},
- "" + (year) + "-W53-" + day);
- } else {
- // A common year starting on between Friday and Sunday will always end with week
- // 52.
- testOp('$isoWeek', newYearsEve, 52);
- testOp('$isoWeekYear', newYearsEve, year);
- testOp('$isoWeek', endOfSecondToLastWeekInYear, 51);
- testOp('$isoWeekYear', endOfSecondToLastWeekInYear, year);
- testOp('$isoWeek', startOfLastWeekInYear, 52);
- testOp('$isoWeekYear', startOfLastWeekInYear, year);
- testOp('$dateToString',
- {format: '%G-W%V-%u', date: newYearsEve},
- "" + (year) + "-W52-" + day);
- }
+ // A common year starting on between Friday and Sunday will always end with week
+ // 52.
+ testOp('$isoWeek', newYearsEve, 52);
+ testOp('$isoWeekYear', newYearsEve, year);
+ testOp('$isoWeek', endOfSecondToLastWeekInYear, 51);
+ testOp('$isoWeekYear', endOfSecondToLastWeekInYear, year);
+ testOp('$isoWeek', startOfLastWeekInYear, 52);
+ testOp('$isoWeekYear', startOfLastWeekInYear, year);
+ testOp('$dateToString',
+ {format: '%G-W%V-%u', date: newYearsEve},
+ "" + (year) + "-W52-" + day);
}
- });
+ }
});
- assert.eq(testOpCount, 485, 'Expected 485 tests to run');
+});
+assert.eq(testOpCount, 485, 'Expected 485 tests to run');
})();
diff --git a/jstests/aggregation/bugs/server7781.js b/jstests/aggregation/bugs/server7781.js
index f755a6af0ad..19700cc2202 100644
--- a/jstests/aggregation/bugs/server7781.js
+++ b/jstests/aggregation/bugs/server7781.js
@@ -4,128 +4,128 @@
// requires_spawning_own_processes,
// ]
(function() {
- 'use strict';
-
- load('jstests/libs/geo_near_random.js');
- load('jstests/aggregation/extras/utils.js');
-
- var coll = 'server7781';
-
+'use strict';
+
+load('jstests/libs/geo_near_random.js');
+load('jstests/aggregation/extras/utils.js');
+
+var coll = 'server7781';
+
+db[coll].drop();
+db[coll].insert({loc: [0, 0]});
+
+// $geoNear is only allowed as the first stage in a pipeline, nowhere else.
+assert.throws(
+ () => db[coll].aggregate(
+ [{$match: {x: 1}}, {$geoNear: {near: [1, 1], spherical: true, distanceField: 'dis'}}]));
+
+const kDistanceField = "dis";
+const kIncludeLocsField = "loc";
+
+/**
+ * Tests the output of the $geoNear command. This function expects a document with the following
+ * fields:
+ * - 'geoNearSpec' is the specification for a $geoNear aggregation stage.
+ * - 'limit' is an integer limiting the number of pipeline results.
+ * - 'batchSize', if specified, is the batchSize to use for the aggregation.
+ */
+function testGeoNearStageOutput({geoNearSpec, limit, batchSize}) {
+ const aggOptions = batchSize ? {batchSize: batchSize} : {};
+ const result =
+ db[coll].aggregate([{$geoNear: geoNearSpec}, {$limit: limit}], aggOptions).toArray();
+ const errmsg = () => tojson(result);
+
+ // Verify that we got the expected number of results.
+ assert.eq(result.length, limit, errmsg);
+
+ // Run though the array, checking for proper sort order and sane computed distances.
+ result.reduce((lastDist, curDoc) => {
+ const curDist = curDoc[kDistanceField];
+
+ // Verify that distances are in increasing order.
+ assert.lte(lastDist, curDist, errmsg);
+
+ // Verify that the computed distance is correct.
+ const computed = Geo.sphereDistance(geoNearSpec["near"], curDoc[kIncludeLocsField]);
+ assert.close(computed, curDist, errmsg);
+ return curDist;
+ }, 0);
+}
+
+// We use this to generate points. Using a single global to avoid reseting RNG in each pass.
+var pointMaker = new GeoNearRandomTest(coll);
+
+function test(db, sharded, indexType) {
db[coll].drop();
- db[coll].insert({loc: [0, 0]});
-
- // $geoNear is only allowed as the first stage in a pipeline, nowhere else.
- assert.throws(
- () => db[coll].aggregate(
- [{$match: {x: 1}}, {$geoNear: {near: [1, 1], spherical: true, distanceField: 'dis'}}]));
-
- const kDistanceField = "dis";
- const kIncludeLocsField = "loc";
-
- /**
- * Tests the output of the $geoNear command. This function expects a document with the following
- * fields:
- * - 'geoNearSpec' is the specification for a $geoNear aggregation stage.
- * - 'limit' is an integer limiting the number of pipeline results.
- * - 'batchSize', if specified, is the batchSize to use for the aggregation.
- */
- function testGeoNearStageOutput({geoNearSpec, limit, batchSize}) {
- const aggOptions = batchSize ? {batchSize: batchSize} : {};
- const result =
- db[coll].aggregate([{$geoNear: geoNearSpec}, {$limit: limit}], aggOptions).toArray();
- const errmsg = () => tojson(result);
-
- // Verify that we got the expected number of results.
- assert.eq(result.length, limit, errmsg);
-
- // Run though the array, checking for proper sort order and sane computed distances.
- result.reduce((lastDist, curDoc) => {
- const curDist = curDoc[kDistanceField];
-
- // Verify that distances are in increasing order.
- assert.lte(lastDist, curDist, errmsg);
-
- // Verify that the computed distance is correct.
- const computed = Geo.sphereDistance(geoNearSpec["near"], curDoc[kIncludeLocsField]);
- assert.close(computed, curDist, errmsg);
- return curDist;
- }, 0);
- }
-
- // We use this to generate points. Using a single global to avoid reseting RNG in each pass.
- var pointMaker = new GeoNearRandomTest(coll);
- function test(db, sharded, indexType) {
- db[coll].drop();
-
- if (sharded) { // sharded setup
- var shards = [];
- var config = db.getSiblingDB("config");
- config.shards.find().forEach(function(shard) {
- shards.push(shard._id);
- });
+ if (sharded) { // sharded setup
+ var shards = [];
+ var config = db.getSiblingDB("config");
+ config.shards.find().forEach(function(shard) {
+ shards.push(shard._id);
+ });
+ assert.commandWorked(
+ db.adminCommand({shardCollection: db[coll].getFullName(), key: {rand: 1}}));
+ for (var i = 1; i < 10; i++) {
+ // split at 0.1, 0.2, ... 0.9
assert.commandWorked(
- db.adminCommand({shardCollection: db[coll].getFullName(), key: {rand: 1}}));
- for (var i = 1; i < 10; i++) {
- // split at 0.1, 0.2, ... 0.9
- assert.commandWorked(
- db.adminCommand({split: db[coll].getFullName(), middle: {rand: i / 10}}));
- db.adminCommand({
- moveChunk: db[coll].getFullName(),
- find: {rand: i / 10},
- to: shards[i % shards.length]
- });
- }
-
- assert.eq(config.chunks.count({'ns': db[coll].getFullName()}), 10);
- }
-
- // insert points
- var numPts = 10 * 1000;
- var bulk = db[coll].initializeUnorderedBulkOp();
- for (var i = 0; i < numPts; i++) {
- bulk.insert({rand: Math.random(), loc: pointMaker.mkPt()});
+ db.adminCommand({split: db[coll].getFullName(), middle: {rand: i / 10}}));
+ db.adminCommand({
+ moveChunk: db[coll].getFullName(),
+ find: {rand: i / 10},
+ to: shards[i % shards.length]
+ });
}
- assert.writeOK(bulk.execute());
-
- assert.eq(db[coll].count(), numPts);
-
- db[coll].ensureIndex({loc: indexType});
-
- // Test $geoNear with spherical coordinates.
- testGeoNearStageOutput({
- geoNearSpec: {
- near: pointMaker.mkPt(0.25),
- distanceField: kDistanceField,
- includeLocs: kIncludeLocsField,
- spherical: true,
- },
- limit: 100
- });
- // Test $geoNear with an initial batchSize of 1.
- testGeoNearStageOutput({
- geoNearSpec: {
- near: pointMaker.mkPt(0.25),
- distanceField: kDistanceField,
- includeLocs: kIncludeLocsField,
- spherical: true,
- },
- limit: 70,
- batchSize: 1
- });
+ assert.eq(config.chunks.count({'ns': db[coll].getFullName()}), 10);
}
- test(db, false, '2d');
- test(db, false, '2dsphere');
-
- var sharded = new ShardingTest({shards: 3, mongos: 1});
- assert.commandWorked(sharded.s0.adminCommand({enablesharding: "test"}));
- sharded.ensurePrimaryShard('test', sharded.shard1.shardName);
-
- test(sharded.getDB('test'), true, '2d');
- test(sharded.getDB('test'), true, '2dsphere');
-
- sharded.stop();
+ // insert points
+ var numPts = 10 * 1000;
+ var bulk = db[coll].initializeUnorderedBulkOp();
+ for (var i = 0; i < numPts; i++) {
+ bulk.insert({rand: Math.random(), loc: pointMaker.mkPt()});
+ }
+ assert.writeOK(bulk.execute());
+
+ assert.eq(db[coll].count(), numPts);
+
+ db[coll].ensureIndex({loc: indexType});
+
+ // Test $geoNear with spherical coordinates.
+ testGeoNearStageOutput({
+ geoNearSpec: {
+ near: pointMaker.mkPt(0.25),
+ distanceField: kDistanceField,
+ includeLocs: kIncludeLocsField,
+ spherical: true,
+ },
+ limit: 100
+ });
+
+ // Test $geoNear with an initial batchSize of 1.
+ testGeoNearStageOutput({
+ geoNearSpec: {
+ near: pointMaker.mkPt(0.25),
+ distanceField: kDistanceField,
+ includeLocs: kIncludeLocsField,
+ spherical: true,
+ },
+ limit: 70,
+ batchSize: 1
+ });
+}
+
+test(db, false, '2d');
+test(db, false, '2dsphere');
+
+var sharded = new ShardingTest({shards: 3, mongos: 1});
+assert.commandWorked(sharded.s0.adminCommand({enablesharding: "test"}));
+sharded.ensurePrimaryShard('test', sharded.shard1.shardName);
+
+test(sharded.getDB('test'), true, '2d');
+test(sharded.getDB('test'), true, '2dsphere');
+
+sharded.stop();
})();
diff --git a/jstests/aggregation/bugs/server8141.js b/jstests/aggregation/bugs/server8141.js
index 9777737517b..908fd952059 100644
--- a/jstests/aggregation/bugs/server8141.js
+++ b/jstests/aggregation/bugs/server8141.js
@@ -1,52 +1,50 @@
// SERVER-8141 Avoid treating arrays as literals in aggregation pipeline.
(function() {
- 'use strict';
- var coll = db.exprs_in_arrays;
- coll.drop();
+'use strict';
+var coll = db.exprs_in_arrays;
+coll.drop();
- assert.writeOK(coll.insert({_id: 0, a: ['foo', 'bar', 'baz'], b: 'bar', c: 'Baz'}));
+assert.writeOK(coll.insert({_id: 0, a: ['foo', 'bar', 'baz'], b: 'bar', c: 'Baz'}));
- // An array of constants should still evaluate to an array of constants.
- var pipeline = [{$project: {_id: 0, d: ['constant', 1]}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{d: ['constant', 1]}]);
+// An array of constants should still evaluate to an array of constants.
+var pipeline = [{$project: {_id: 0, d: ['constant', 1]}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{d: ['constant', 1]}]);
- // A field name inside an array should take on the value of that field.
- pipeline = [{$project: {_id: 0, d: ['$b']}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{d: ['bar']}]);
+// A field name inside an array should take on the value of that field.
+pipeline = [{$project: {_id: 0, d: ['$b']}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{d: ['bar']}]);
- // An expression inside an array should be evaluated.
- pipeline = [{$project: {_id: 0, d: [{$toLower: 'FoO'}]}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{d: ['foo']}]);
+// An expression inside an array should be evaluated.
+pipeline = [{$project: {_id: 0, d: [{$toLower: 'FoO'}]}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{d: ['foo']}]);
- // Both an expression and a field name inside an array should be evaluated.
- pipeline = [{$project: {_id: 0, d: ['$b', {$toLower: 'FoO'}]}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{d: ['bar', 'foo']}]);
+// Both an expression and a field name inside an array should be evaluated.
+pipeline = [{$project: {_id: 0, d: ['$b', {$toLower: 'FoO'}]}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{d: ['bar', 'foo']}]);
- // A nested array should still be evaluated.
- pipeline = [{$project: {_id: 0, d: ['$b', 'constant', [1, {$toLower: 'FoO'}]]}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{d: ['bar', 'constant', [1, 'foo']]}]);
+// A nested array should still be evaluated.
+pipeline = [{$project: {_id: 0, d: ['$b', 'constant', [1, {$toLower: 'FoO'}]]}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{d: ['bar', 'constant', [1, 'foo']]}]);
- // Should still evaluate array elements inside arguments to an expression.
- pipeline = [{$project: {_id: 0, d: {$setIntersection: ['$a', ['$b']]}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{d: ['bar']}]);
+// Should still evaluate array elements inside arguments to an expression.
+pipeline = [{$project: {_id: 0, d: {$setIntersection: ['$a', ['$b']]}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{d: ['bar']}]);
- pipeline = [{$project: {_id: 0, d: {$setIntersection: ['$a', [{$toLower: 'FoO'}]]}}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{d: ['foo']}]);
+pipeline = [{$project: {_id: 0, d: {$setIntersection: ['$a', [{$toLower: 'FoO'}]]}}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{d: ['foo']}]);
- // Nested arrays.
- pipeline = [{
- $project: {
- _id: 0,
- d: {$setIntersection: [[[1, 'foo', 'bar']], [[1, {$toLower: 'FoO'}, '$b']]]}
- }
- }];
- assert.eq(coll.aggregate(pipeline).toArray(), [{d: [[1, 'foo', 'bar']]}]);
+// Nested arrays.
+pipeline = [{
+ $project:
+ {_id: 0, d: {$setIntersection: [[[1, 'foo', 'bar']], [[1, {$toLower: 'FoO'}, '$b']]]}}
+}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{d: [[1, 'foo', 'bar']]}]);
- coll.drop();
+coll.drop();
- // Should replace missing values with NULL to preserve indices.
- assert.writeOK(coll.insert({_id: 1, x: 1, z: 2}));
+// Should replace missing values with NULL to preserve indices.
+assert.writeOK(coll.insert({_id: 1, x: 1, z: 2}));
- pipeline = [{$project: {_id: 0, coordinate: ['$x', '$y', '$z']}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{coordinate: [1, null, 2]}]);
+pipeline = [{$project: {_id: 0, coordinate: ['$x', '$y', '$z']}}];
+assert.eq(coll.aggregate(pipeline).toArray(), [{coordinate: [1, null, 2]}]);
}());
diff --git a/jstests/aggregation/bugs/server8164.js b/jstests/aggregation/bugs/server8164.js
index 89cb360d91f..5b137b18d87 100644
--- a/jstests/aggregation/bugs/server8164.js
+++ b/jstests/aggregation/bugs/server8164.js
@@ -1,144 +1,144 @@
// SERVER-8164: ISODate doesn't handle years less than 100 properly.
(function() {
- assert.eq(tojson(ISODate("0000-01-01")), 'ISODate("0000-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("0000-01-01T00:00:00")), 'ISODate("0000-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("0000-01-01T00:00:00Z")), 'ISODate("0000-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("0000-01-01T00:00:00.123")), 'ISODate("0000-01-01T00:00:00.123Z")');
- assert.eq(tojson(ISODate("0000-01-01T00:00:00.123Z")), 'ISODate("0000-01-01T00:00:00.123Z")');
-
- assert.eq(tojson(ISODate("0000-01-01T00:00:00.1Z")), 'ISODate("0000-01-01T00:00:00.100Z")');
- assert.eq(tojson(ISODate("0000-01-01T00:00:00.10Z")), 'ISODate("0000-01-01T00:00:00.100Z")');
- assert.eq(tojson(ISODate("0000-01-01T00:00:00.100Z")), 'ISODate("0000-01-01T00:00:00.100Z")');
- assert.eq(tojson(ISODate("0000-01-01T00:00:00.1000Z")), 'ISODate("0000-01-01T00:00:00.100Z")');
-
- assert.eq(tojson(ISODate("0000-01-01T00:00:00.1234Z")), 'ISODate("0000-01-01T00:00:00.123Z")');
- assert.eq(tojson(ISODate("0000-01-01T00:00:00.1235Z")), 'ISODate("0000-01-01T00:00:00.124Z")');
-
- /* Testing different years */
- assert.eq(tojson(ISODate("0000-01-01T00:00:00Z")), 'ISODate("0000-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("0001-01-01T00:00:00Z")), 'ISODate("0001-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("0069-01-01T00:00:00Z")), 'ISODate("0069-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("0070-01-01T00:00:00Z")), 'ISODate("0070-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("0099-01-01T00:00:00Z")), 'ISODate("0099-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("0100-01-01T00:00:00Z")), 'ISODate("0100-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("1800-01-01T00:00:00Z")), 'ISODate("1800-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("1801-01-01T00:00:00Z")), 'ISODate("1801-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("1869-01-01T00:00:00Z")), 'ISODate("1869-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("1870-01-01T00:00:00Z")), 'ISODate("1870-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("1899-01-01T00:00:00Z")), 'ISODate("1899-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("1900-01-01T00:00:00Z")), 'ISODate("1900-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("1901-01-01T00:00:00Z")), 'ISODate("1901-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("1969-01-01T00:00:00Z")), 'ISODate("1969-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("1970-01-01T00:00:00Z")), 'ISODate("1970-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("1999-01-01T00:00:00Z")), 'ISODate("1999-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("2000-01-01T00:00:00Z")), 'ISODate("2000-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("2001-01-01T00:00:00Z")), 'ISODate("2001-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("2069-01-01T00:00:00Z")), 'ISODate("2069-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("2070-01-01T00:00:00Z")), 'ISODate("2070-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("2099-01-01T00:00:00Z")), 'ISODate("2099-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("9999-01-01T00:00:00Z")), 'ISODate("9999-01-01T00:00:00Z")');
-
- /* Testing without - in date and : in time */
- assert.eq(tojson(ISODate("19980101T00:00:00Z")), 'ISODate("1998-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("1999-0101T00:00:00Z")), 'ISODate("1999-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("200001-01T00:00:00Z")), 'ISODate("2000-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("1998-01-01T000000Z")), 'ISODate("1998-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("1999-01-01T00:0000Z")), 'ISODate("1999-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("2000-01-01T0000:00Z")), 'ISODate("2000-01-01T00:00:00Z")');
-
- /* Testing field overflows */
- assert.eq(tojson(ISODate("0000-01-01T00:00:60Z")), 'ISODate("0000-01-01T00:01:00Z")');
- assert.eq(tojson(ISODate("0000-01-01T00:00:99Z")), 'ISODate("0000-01-01T00:01:39Z")');
-
- assert.eq(tojson(ISODate("0000-01-01T00:60:00Z")), 'ISODate("0000-01-01T01:00:00Z")');
- assert.eq(tojson(ISODate("0000-01-01T00:99:00Z")), 'ISODate("0000-01-01T01:39:00Z")');
-
- assert.eq(tojson(ISODate("0000-01-01T24:00:00Z")), 'ISODate("0000-01-02T00:00:00Z")');
- assert.eq(tojson(ISODate("0000-01-01T99:00:00Z")), 'ISODate("0000-01-05T03:00:00Z")');
-
- assert.eq(tojson(ISODate("0000-01-32T00:00:00Z")), 'ISODate("0000-02-01T00:00:00Z")');
- assert.eq(tojson(ISODate("0000-01-99T00:00:00Z")), 'ISODate("0000-04-08T00:00:00Z")');
- assert.eq(tojson(ISODate("0000-02-29T00:00:00Z")), 'ISODate("0000-02-29T00:00:00Z")');
- assert.eq(tojson(ISODate("0000-02-30T00:00:00Z")), 'ISODate("0000-03-01T00:00:00Z")');
- assert.eq(tojson(ISODate("0000-02-31T00:00:00Z")), 'ISODate("0000-03-02T00:00:00Z")');
- assert.eq(tojson(ISODate("0000-02-99T00:00:00Z")), 'ISODate("0000-05-09T00:00:00Z")');
-
- assert.eq(tojson(ISODate("0001-02-29T00:00:00Z")), 'ISODate("0001-03-01T00:00:00Z")');
- assert.eq(tojson(ISODate("0001-02-30T00:00:00Z")), 'ISODate("0001-03-02T00:00:00Z")');
- assert.eq(tojson(ISODate("0001-02-31T00:00:00Z")), 'ISODate("0001-03-03T00:00:00Z")');
- assert.eq(tojson(ISODate("0001-02-99T00:00:00Z")), 'ISODate("0001-05-10T00:00:00Z")');
-
- assert.eq(tojson(ISODate("0000-13-01T00:00:00Z")), 'ISODate("0001-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("0000-99-01T00:00:00Z")), 'ISODate("0008-03-01T00:00:00Z")');
-
- /* Testing GMT offset instead of Z */
- assert.eq(tojson(ISODate("0001-01-01T00:00:00+01")), 'ISODate("0000-12-31T23:00:00Z")');
- assert.eq(tojson(ISODate("0001-01-01T00:00:00+99")), 'ISODate("0000-12-27T21:00:00Z")');
-
- assert.eq(tojson(ISODate("0001-01-01T00:00:00-01")), 'ISODate("0001-01-01T01:00:00Z")');
- assert.eq(tojson(ISODate("0001-01-01T00:00:00-99")), 'ISODate("0001-01-05T03:00:00Z")');
-
- assert.eq(tojson(ISODate("0001-01-01T00:00:00+0100")), 'ISODate("0000-12-31T23:00:00Z")');
- assert.eq(tojson(ISODate("0001-01-01T00:00:00+0160")), 'ISODate("0000-12-31T22:00:00Z")');
- assert.eq(tojson(ISODate("0001-01-01T00:00:00+0199")), 'ISODate("0000-12-31T21:21:00Z")');
- assert.eq(tojson(ISODate("0001-01-01T00:00:00+9999")), 'ISODate("0000-12-27T19:21:00Z")');
-
- assert.eq(tojson(ISODate("0001-01-01T00:00:00-0100")), 'ISODate("0001-01-01T01:00:00Z")');
- assert.eq(tojson(ISODate("0001-01-01T00:00:00-0160")), 'ISODate("0001-01-01T02:00:00Z")');
- assert.eq(tojson(ISODate("0001-01-01T00:00:00-0199")), 'ISODate("0001-01-01T02:39:00Z")');
- assert.eq(tojson(ISODate("0001-01-01T00:00:00-9999")), 'ISODate("0001-01-05T04:39:00Z")');
-
- assert.eq(tojson(ISODate("0001-01-01T00:00:00+01:00")), 'ISODate("0000-12-31T23:00:00Z")');
- assert.eq(tojson(ISODate("0001-01-01T00:00:00+01:60")), 'ISODate("0000-12-31T22:00:00Z")');
- assert.eq(tojson(ISODate("0001-01-01T00:00:00+01:99")), 'ISODate("0000-12-31T21:21:00Z")');
- assert.eq(tojson(ISODate("0001-01-01T00:00:00+99:99")), 'ISODate("0000-12-27T19:21:00Z")');
-
- assert.eq(tojson(ISODate("0001-01-01T00:00:00-01:00")), 'ISODate("0001-01-01T01:00:00Z")');
- assert.eq(tojson(ISODate("0001-01-01T00:00:00-01:60")), 'ISODate("0001-01-01T02:00:00Z")');
- assert.eq(tojson(ISODate("0001-01-01T00:00:00-01:99")), 'ISODate("0001-01-01T02:39:00Z")');
- assert.eq(tojson(ISODate("0001-01-01T00:00:00-99:99")), 'ISODate("0001-01-05T04:39:00Z")');
-
- /* Testing field underflows */
- assert.eq(tojson(ISODate("0001-01-00T00:00:00Z")), 'ISODate("0000-12-31T00:00:00Z")');
- assert.eq(tojson(ISODate("0001-00-00T00:00:00Z")), 'ISODate("0000-11-30T00:00:00Z")');
- assert.eq(tojson(ISODate("0001-00-01T00:00:00Z")), 'ISODate("0000-12-01T00:00:00Z")');
-
- /* Testing lowest and highest */
- assert.eq(tojson(ISODate("0000-01-01T00:00:00Z")), 'ISODate("0000-01-01T00:00:00Z")');
- assert.eq(tojson(ISODate("9999-12-31T23:59:59.999Z")), 'ISODate("9999-12-31T23:59:59.999Z")');
-
- /* Testing out of range */
+assert.eq(tojson(ISODate("0000-01-01")), 'ISODate("0000-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("0000-01-01T00:00:00")), 'ISODate("0000-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("0000-01-01T00:00:00Z")), 'ISODate("0000-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("0000-01-01T00:00:00.123")), 'ISODate("0000-01-01T00:00:00.123Z")');
+assert.eq(tojson(ISODate("0000-01-01T00:00:00.123Z")), 'ISODate("0000-01-01T00:00:00.123Z")');
+
+assert.eq(tojson(ISODate("0000-01-01T00:00:00.1Z")), 'ISODate("0000-01-01T00:00:00.100Z")');
+assert.eq(tojson(ISODate("0000-01-01T00:00:00.10Z")), 'ISODate("0000-01-01T00:00:00.100Z")');
+assert.eq(tojson(ISODate("0000-01-01T00:00:00.100Z")), 'ISODate("0000-01-01T00:00:00.100Z")');
+assert.eq(tojson(ISODate("0000-01-01T00:00:00.1000Z")), 'ISODate("0000-01-01T00:00:00.100Z")');
+
+assert.eq(tojson(ISODate("0000-01-01T00:00:00.1234Z")), 'ISODate("0000-01-01T00:00:00.123Z")');
+assert.eq(tojson(ISODate("0000-01-01T00:00:00.1235Z")), 'ISODate("0000-01-01T00:00:00.124Z")');
+
+/* Testing different years */
+assert.eq(tojson(ISODate("0000-01-01T00:00:00Z")), 'ISODate("0000-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("0001-01-01T00:00:00Z")), 'ISODate("0001-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("0069-01-01T00:00:00Z")), 'ISODate("0069-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("0070-01-01T00:00:00Z")), 'ISODate("0070-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("0099-01-01T00:00:00Z")), 'ISODate("0099-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("0100-01-01T00:00:00Z")), 'ISODate("0100-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("1800-01-01T00:00:00Z")), 'ISODate("1800-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("1801-01-01T00:00:00Z")), 'ISODate("1801-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("1869-01-01T00:00:00Z")), 'ISODate("1869-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("1870-01-01T00:00:00Z")), 'ISODate("1870-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("1899-01-01T00:00:00Z")), 'ISODate("1899-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("1900-01-01T00:00:00Z")), 'ISODate("1900-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("1901-01-01T00:00:00Z")), 'ISODate("1901-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("1969-01-01T00:00:00Z")), 'ISODate("1969-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("1970-01-01T00:00:00Z")), 'ISODate("1970-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("1999-01-01T00:00:00Z")), 'ISODate("1999-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("2000-01-01T00:00:00Z")), 'ISODate("2000-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("2001-01-01T00:00:00Z")), 'ISODate("2001-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("2069-01-01T00:00:00Z")), 'ISODate("2069-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("2070-01-01T00:00:00Z")), 'ISODate("2070-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("2099-01-01T00:00:00Z")), 'ISODate("2099-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("9999-01-01T00:00:00Z")), 'ISODate("9999-01-01T00:00:00Z")');
+
+/* Testing without - in date and : in time */
+assert.eq(tojson(ISODate("19980101T00:00:00Z")), 'ISODate("1998-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("1999-0101T00:00:00Z")), 'ISODate("1999-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("200001-01T00:00:00Z")), 'ISODate("2000-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("1998-01-01T000000Z")), 'ISODate("1998-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("1999-01-01T00:0000Z")), 'ISODate("1999-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("2000-01-01T0000:00Z")), 'ISODate("2000-01-01T00:00:00Z")');
+
+/* Testing field overflows */
+assert.eq(tojson(ISODate("0000-01-01T00:00:60Z")), 'ISODate("0000-01-01T00:01:00Z")');
+assert.eq(tojson(ISODate("0000-01-01T00:00:99Z")), 'ISODate("0000-01-01T00:01:39Z")');
+
+assert.eq(tojson(ISODate("0000-01-01T00:60:00Z")), 'ISODate("0000-01-01T01:00:00Z")');
+assert.eq(tojson(ISODate("0000-01-01T00:99:00Z")), 'ISODate("0000-01-01T01:39:00Z")');
+
+assert.eq(tojson(ISODate("0000-01-01T24:00:00Z")), 'ISODate("0000-01-02T00:00:00Z")');
+assert.eq(tojson(ISODate("0000-01-01T99:00:00Z")), 'ISODate("0000-01-05T03:00:00Z")');
+
+assert.eq(tojson(ISODate("0000-01-32T00:00:00Z")), 'ISODate("0000-02-01T00:00:00Z")');
+assert.eq(tojson(ISODate("0000-01-99T00:00:00Z")), 'ISODate("0000-04-08T00:00:00Z")');
+assert.eq(tojson(ISODate("0000-02-29T00:00:00Z")), 'ISODate("0000-02-29T00:00:00Z")');
+assert.eq(tojson(ISODate("0000-02-30T00:00:00Z")), 'ISODate("0000-03-01T00:00:00Z")');
+assert.eq(tojson(ISODate("0000-02-31T00:00:00Z")), 'ISODate("0000-03-02T00:00:00Z")');
+assert.eq(tojson(ISODate("0000-02-99T00:00:00Z")), 'ISODate("0000-05-09T00:00:00Z")');
+
+assert.eq(tojson(ISODate("0001-02-29T00:00:00Z")), 'ISODate("0001-03-01T00:00:00Z")');
+assert.eq(tojson(ISODate("0001-02-30T00:00:00Z")), 'ISODate("0001-03-02T00:00:00Z")');
+assert.eq(tojson(ISODate("0001-02-31T00:00:00Z")), 'ISODate("0001-03-03T00:00:00Z")');
+assert.eq(tojson(ISODate("0001-02-99T00:00:00Z")), 'ISODate("0001-05-10T00:00:00Z")');
+
+assert.eq(tojson(ISODate("0000-13-01T00:00:00Z")), 'ISODate("0001-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("0000-99-01T00:00:00Z")), 'ISODate("0008-03-01T00:00:00Z")');
+
+/* Testing GMT offset instead of Z */
+assert.eq(tojson(ISODate("0001-01-01T00:00:00+01")), 'ISODate("0000-12-31T23:00:00Z")');
+assert.eq(tojson(ISODate("0001-01-01T00:00:00+99")), 'ISODate("0000-12-27T21:00:00Z")');
+
+assert.eq(tojson(ISODate("0001-01-01T00:00:00-01")), 'ISODate("0001-01-01T01:00:00Z")');
+assert.eq(tojson(ISODate("0001-01-01T00:00:00-99")), 'ISODate("0001-01-05T03:00:00Z")');
+
+assert.eq(tojson(ISODate("0001-01-01T00:00:00+0100")), 'ISODate("0000-12-31T23:00:00Z")');
+assert.eq(tojson(ISODate("0001-01-01T00:00:00+0160")), 'ISODate("0000-12-31T22:00:00Z")');
+assert.eq(tojson(ISODate("0001-01-01T00:00:00+0199")), 'ISODate("0000-12-31T21:21:00Z")');
+assert.eq(tojson(ISODate("0001-01-01T00:00:00+9999")), 'ISODate("0000-12-27T19:21:00Z")');
+
+assert.eq(tojson(ISODate("0001-01-01T00:00:00-0100")), 'ISODate("0001-01-01T01:00:00Z")');
+assert.eq(tojson(ISODate("0001-01-01T00:00:00-0160")), 'ISODate("0001-01-01T02:00:00Z")');
+assert.eq(tojson(ISODate("0001-01-01T00:00:00-0199")), 'ISODate("0001-01-01T02:39:00Z")');
+assert.eq(tojson(ISODate("0001-01-01T00:00:00-9999")), 'ISODate("0001-01-05T04:39:00Z")');
+
+assert.eq(tojson(ISODate("0001-01-01T00:00:00+01:00")), 'ISODate("0000-12-31T23:00:00Z")');
+assert.eq(tojson(ISODate("0001-01-01T00:00:00+01:60")), 'ISODate("0000-12-31T22:00:00Z")');
+assert.eq(tojson(ISODate("0001-01-01T00:00:00+01:99")), 'ISODate("0000-12-31T21:21:00Z")');
+assert.eq(tojson(ISODate("0001-01-01T00:00:00+99:99")), 'ISODate("0000-12-27T19:21:00Z")');
+
+assert.eq(tojson(ISODate("0001-01-01T00:00:00-01:00")), 'ISODate("0001-01-01T01:00:00Z")');
+assert.eq(tojson(ISODate("0001-01-01T00:00:00-01:60")), 'ISODate("0001-01-01T02:00:00Z")');
+assert.eq(tojson(ISODate("0001-01-01T00:00:00-01:99")), 'ISODate("0001-01-01T02:39:00Z")');
+assert.eq(tojson(ISODate("0001-01-01T00:00:00-99:99")), 'ISODate("0001-01-05T04:39:00Z")');
+
+/* Testing field underflows */
+assert.eq(tojson(ISODate("0001-01-00T00:00:00Z")), 'ISODate("0000-12-31T00:00:00Z")');
+assert.eq(tojson(ISODate("0001-00-00T00:00:00Z")), 'ISODate("0000-11-30T00:00:00Z")');
+assert.eq(tojson(ISODate("0001-00-01T00:00:00Z")), 'ISODate("0000-12-01T00:00:00Z")');
+
+/* Testing lowest and highest */
+assert.eq(tojson(ISODate("0000-01-01T00:00:00Z")), 'ISODate("0000-01-01T00:00:00Z")');
+assert.eq(tojson(ISODate("9999-12-31T23:59:59.999Z")), 'ISODate("9999-12-31T23:59:59.999Z")');
+
+/* Testing out of range */
+assert.throws(function() {
+ tojson(ISODate("0000-01-00T23:59:59.999Z"));
+});
+assert.throws(function() {
+ tojson(ISODate("9999-12-31T23:59:60Z"));
+});
+
+/* Testing broken format */
+var brokenFormatTests = [
+ "2017",
+ "2017-09",
+ "2017-09-16T18:37 25Z",
+ "2017-09-16T18 37:25Z",
+ "2017-09-16X18:37:25Z",
+ "2017-09 16T18:37:25Z",
+ "2017 09-16T18:37:25Z",
+ "2017-09-16T18:37:25 123Z",
+ "2017-09-16T18:37:25 0600",
+];
+
+brokenFormatTests.forEach(function(test) {
assert.throws(function() {
- tojson(ISODate("0000-01-00T23:59:59.999Z"));
- });
- assert.throws(function() {
- tojson(ISODate("9999-12-31T23:59:60Z"));
- });
-
- /* Testing broken format */
- var brokenFormatTests = [
- "2017",
- "2017-09",
- "2017-09-16T18:37 25Z",
- "2017-09-16T18 37:25Z",
- "2017-09-16X18:37:25Z",
- "2017-09 16T18:37:25Z",
- "2017 09-16T18:37:25Z",
- "2017-09-16T18:37:25 123Z",
- "2017-09-16T18:37:25 0600",
- ];
-
- brokenFormatTests.forEach(function(test) {
- assert.throws(function() {
- print(tojson(ISODate(test)));
- }, [tojson(test)]);
- });
-
- /* Testing conversion to milliseconds */
- assert.eq(ISODate("1969-12-31T23:59:59.999Z"), new Date(-1));
- assert.eq(ISODate("1969-12-31T23:59:59.000Z"), new Date(-1000));
- assert.eq(ISODate("1900-01-01T00:00:00.000Z"), new Date(-2208988800000));
- assert.eq(ISODate("1899-12-31T23:59:59.999Z"), new Date(-2208988800001));
- assert.eq(ISODate("0000-01-01T00:00:00.000Z"), new Date(-62167219200000));
- assert.eq(ISODate("9999-12-31T23:59:59.999Z"), new Date(253402300799999));
+ print(tojson(ISODate(test)));
+ }, [tojson(test)]);
+});
+
+/* Testing conversion to milliseconds */
+assert.eq(ISODate("1969-12-31T23:59:59.999Z"), new Date(-1));
+assert.eq(ISODate("1969-12-31T23:59:59.000Z"), new Date(-1000));
+assert.eq(ISODate("1900-01-01T00:00:00.000Z"), new Date(-2208988800000));
+assert.eq(ISODate("1899-12-31T23:59:59.999Z"), new Date(-2208988800001));
+assert.eq(ISODate("0000-01-01T00:00:00.000Z"), new Date(-62167219200000));
+assert.eq(ISODate("9999-12-31T23:59:59.999Z"), new Date(253402300799999));
}());
diff --git a/jstests/aggregation/bugs/server8568.js b/jstests/aggregation/bugs/server8568.js
index ae9a9ad8202..71793f5696b 100644
--- a/jstests/aggregation/bugs/server8568.js
+++ b/jstests/aggregation/bugs/server8568.js
@@ -4,40 +4,40 @@
load('jstests/aggregation/extras/utils.js');
(function() {
- 'use strict';
- var coll = db.sqrt;
- coll.drop();
- assert.writeOK(coll.insert({_id: 0}));
-
- // 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}]);
- }
-
- // Helper for testing that op results in error with code errorCode.
- function testError(op, errorCode) {
- var pipeline = [{$project: {_id: 0, result: op}}];
- assertErrorCode(coll, pipeline, errorCode);
- }
-
- // Valid input: Numeric arg >= 0, null, or NaN.
-
- testOp({$sqrt: [100]}, 10);
- testOp({$sqrt: [0]}, 0);
- // All types converted to doubles.
- testOp({$sqrt: [NumberLong("100")]}, 10);
- // LLONG_MAX is converted to a double.
- testOp({$sqrt: [NumberLong("9223372036854775807")]}, 3037000499.97605);
- // Null inputs result in null.
- testOp({$sqrt: [null]}, null);
- // NaN inputs result in NaN.
- testOp({$sqrt: [NaN]}, NaN);
-
- // Invalid input: non-numeric/non-null, arg is negative.
-
- // Arg must be numeric or null.
- testError({$sqrt: ["string"]}, 28765);
- // Args cannot be negative.
- testError({$sqrt: [-1]}, 28714);
+'use strict';
+var coll = db.sqrt;
+coll.drop();
+assert.writeOK(coll.insert({_id: 0}));
+
+// 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}]);
+}
+
+// Helper for testing that op results in error with code errorCode.
+function testError(op, errorCode) {
+ var pipeline = [{$project: {_id: 0, result: op}}];
+ assertErrorCode(coll, pipeline, errorCode);
+}
+
+// Valid input: Numeric arg >= 0, null, or NaN.
+
+testOp({$sqrt: [100]}, 10);
+testOp({$sqrt: [0]}, 0);
+// All types converted to doubles.
+testOp({$sqrt: [NumberLong("100")]}, 10);
+// LLONG_MAX is converted to a double.
+testOp({$sqrt: [NumberLong("9223372036854775807")]}, 3037000499.97605);
+// Null inputs result in null.
+testOp({$sqrt: [null]}, null);
+// NaN inputs result in NaN.
+testOp({$sqrt: [NaN]}, NaN);
+
+// Invalid input: non-numeric/non-null, arg is negative.
+
+// Arg must be numeric or null.
+testError({$sqrt: ["string"]}, 28765);
+// Args cannot be negative.
+testError({$sqrt: [-1]}, 28714);
}());
diff --git a/jstests/aggregation/bugs/server8581.js b/jstests/aggregation/bugs/server8581.js
index 54b97be3d08..fa81578ccbd 100644
--- a/jstests/aggregation/bugs/server8581.js
+++ b/jstests/aggregation/bugs/server8581.js
@@ -79,47 +79,47 @@ a3result = [{
a4result = [
{
- _id: 1,
- level: 1,
- b: {
- level: 3,
- c: 5,
- d: [{level: 1, e: 4}, {f: 6}, "NOT AN OBJECT!!11!", [2, 3, 4, {level: 1, r: 11}]]
- },
- h: {level: 2, i: {level: 4, j: {level: 1, k: 8}}},
- l: {m: {level: 3, n: 12}},
- o: [],
- q: 14
+ _id: 1,
+ level: 1,
+ b: {
+ level: 3,
+ c: 5,
+ d: [{level: 1, e: 4}, {f: 6}, "NOT AN OBJECT!!11!", [2, 3, 4, {level: 1, r: 11}]]
+ },
+ h: {level: 2, i: {level: 4, j: {level: 1, k: 8}}},
+ l: {m: {level: 3, n: 12}},
+ o: [],
+ q: 14
},
{
- _id: 2,
- level: 4,
+ _id: 2,
+ level: 4,
}
];
a5result = [
{
- _id: 1,
- level: 1,
- b: {
- level: 3,
- c: 5,
- d: [
- {level: 1, e: 4},
- {f: 6},
- {level: 5, g: 9},
- "NOT AN OBJECT!!11!",
- [2, 3, 4, {level: 1, r: 11}, {level: 5, s: 99}]
- ]
- },
- h: {level: 2, i: {level: 4, j: {level: 1, k: 8}}},
- l: {m: {level: 3, n: 12}},
- o: [{level: 5, p: 19}],
- q: 14
+ _id: 1,
+ level: 1,
+ b: {
+ level: 3,
+ c: 5,
+ d: [
+ {level: 1, e: 4},
+ {f: 6},
+ {level: 5, g: 9},
+ "NOT AN OBJECT!!11!",
+ [2, 3, 4, {level: 1, r: 11}, {level: 5, s: 99}]
+ ]
+ },
+ h: {level: 2, i: {level: 4, j: {level: 1, k: 8}}},
+ l: {m: {level: 3, n: 12}},
+ o: [{level: 5, p: 19}],
+ q: 14
},
{
- _id: 2,
- level: 4,
+ _id: 2,
+ level: 4,
}
];
diff --git a/jstests/aggregation/bugs/server9444.js b/jstests/aggregation/bugs/server9444.js
index f3c6a449fad..6bb554c8e62 100644
--- a/jstests/aggregation/bugs/server9444.js
+++ b/jstests/aggregation/bugs/server9444.js
@@ -1,64 +1,64 @@
// server-9444 support disk storage of intermediate results in aggregation
(function() {
- 'use strict';
+'use strict';
- load('jstests/libs/fixture_helpers.js'); // For 'FixtureHelpers'
+load('jstests/libs/fixture_helpers.js'); // For 'FixtureHelpers'
- const t = db.server9444;
- t.drop();
+const t = db.server9444;
+t.drop();
- const sharded = FixtureHelpers.isSharded(t);
+const sharded = FixtureHelpers.isSharded(t);
- var memoryLimitMB = sharded ? 200 : 100;
+var memoryLimitMB = sharded ? 200 : 100;
- function loadData() {
- var bigStr = Array(1024 * 1024 + 1).toString(); // 1MB of ','
- for (var i = 0; i < memoryLimitMB + 1; i++)
- t.insert({_id: i, bigStr: i + bigStr, random: Math.random()});
+function loadData() {
+ var bigStr = Array(1024 * 1024 + 1).toString(); // 1MB of ','
+ for (var i = 0; i < memoryLimitMB + 1; i++)
+ t.insert({_id: i, bigStr: i + bigStr, random: Math.random()});
- assert.gt(t.stats().size, memoryLimitMB * 1024 * 1024);
- }
- loadData();
+ assert.gt(t.stats().size, memoryLimitMB * 1024 * 1024);
+}
+loadData();
- function test(pipeline, outOfMemoryCode) {
- // ensure by default we error out if exceeding memory limit
- var res = t.runCommand('aggregate', {pipeline: pipeline, cursor: {}});
- assert.commandFailed(res);
- assert.eq(res.code, outOfMemoryCode);
+function test(pipeline, outOfMemoryCode) {
+ // ensure by default we error out if exceeding memory limit
+ var res = t.runCommand('aggregate', {pipeline: pipeline, cursor: {}});
+ assert.commandFailed(res);
+ assert.eq(res.code, outOfMemoryCode);
- // ensure allowDiskUse: false does what it says
- res = t.runCommand('aggregate', {pipeline: pipeline, cursor: {}, allowDiskUse: false});
- assert.commandFailed(res);
- assert.eq(res.code, outOfMemoryCode);
+ // ensure allowDiskUse: false does what it says
+ res = t.runCommand('aggregate', {pipeline: pipeline, cursor: {}, allowDiskUse: false});
+ assert.commandFailed(res);
+ assert.eq(res.code, outOfMemoryCode);
- // allowDiskUse only supports bool. In particular, numbers aren't allowed.
- res = t.runCommand('aggregate', {pipeline: pipeline, cursor: {}, allowDiskUse: 1});
- assert.commandFailed(res);
+ // allowDiskUse only supports bool. In particular, numbers aren't allowed.
+ res = t.runCommand('aggregate', {pipeline: pipeline, cursor: {}, allowDiskUse: 1});
+ assert.commandFailed(res);
- // ensure we work when allowDiskUse === true
- res = t.aggregate(pipeline, {allowDiskUse: true});
- assert.eq(res.itcount(), t.count()); // all tests output one doc per input doc
- }
+ // ensure we work when allowDiskUse === true
+ res = t.aggregate(pipeline, {allowDiskUse: true});
+ assert.eq(res.itcount(), t.count()); // all tests output one doc per input doc
+}
- var groupCode = 16945;
- var sortCode = 16819;
- var sortLimitCode = 16820;
+var groupCode = 16945;
+var sortCode = 16819;
+var sortLimitCode = 16820;
- test([{$group: {_id: '$_id', bigStr: {$min: '$bigStr'}}}], groupCode);
+test([{$group: {_id: '$_id', bigStr: {$min: '$bigStr'}}}], groupCode);
- // sorting with _id would use index which doesn't require extsort
- test([{$sort: {random: 1}}], sortCode);
- test([{$sort: {bigStr: 1}}], sortCode); // big key and value
+// sorting with _id would use index which doesn't require extsort
+test([{$sort: {random: 1}}], sortCode);
+test([{$sort: {bigStr: 1}}], sortCode); // big key and value
- // make sure sort + large limit won't crash the server (SERVER-10136)
- test([{$sort: {bigStr: 1}}, {$limit: 1000 * 1000 * 1000}], sortLimitCode);
+// make sure sort + large limit won't crash the server (SERVER-10136)
+test([{$sort: {bigStr: 1}}, {$limit: 1000 * 1000 * 1000}], sortLimitCode);
- // test combining two extSorts in both same and different orders
- test([{$group: {_id: '$_id', bigStr: {$min: '$bigStr'}}}, {$sort: {_id: 1}}], groupCode);
- test([{$group: {_id: '$_id', bigStr: {$min: '$bigStr'}}}, {$sort: {_id: -1}}], groupCode);
- test([{$group: {_id: '$_id', bigStr: {$min: '$bigStr'}}}, {$sort: {random: 1}}], groupCode);
- test([{$sort: {random: 1}}, {$group: {_id: '$_id', bigStr: {$first: '$bigStr'}}}], sortCode);
+// test combining two extSorts in both same and different orders
+test([{$group: {_id: '$_id', bigStr: {$min: '$bigStr'}}}, {$sort: {_id: 1}}], groupCode);
+test([{$group: {_id: '$_id', bigStr: {$min: '$bigStr'}}}, {$sort: {_id: -1}}], groupCode);
+test([{$group: {_id: '$_id', bigStr: {$min: '$bigStr'}}}, {$sort: {random: 1}}], groupCode);
+test([{$sort: {random: 1}}, {$group: {_id: '$_id', bigStr: {$first: '$bigStr'}}}], sortCode);
- // don't leave large collection laying around
- t.drop();
+// don't leave large collection laying around
+t.drop();
})();
diff --git a/jstests/aggregation/bugs/server9625.js b/jstests/aggregation/bugs/server9625.js
index 4a525aba518..4cbf487b5e0 100644
--- a/jstests/aggregation/bugs/server9625.js
+++ b/jstests/aggregation/bugs/server9625.js
@@ -5,70 +5,70 @@
load('jstests/aggregation/extras/utils.js');
(function() {
- 'use strict';
- var coll = db.server9625;
- coll.drop();
- assert.writeOK(coll.insert({}));
+'use strict';
+var coll = db.server9625;
+coll.drop();
+assert.writeOK(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}]);
- }
+// 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);
+// 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);
+// 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);
+// 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.writeOK(coll.insert({"a": 1, "b": 6}));
+// 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.writeOK(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 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);
+// 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);
+// 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);
}());
diff --git a/jstests/aggregation/bugs/skip_limit_overflow.js b/jstests/aggregation/bugs/skip_limit_overflow.js
index f0d7e0b27c7..50e665b178f 100644
--- a/jstests/aggregation/bugs/skip_limit_overflow.js
+++ b/jstests/aggregation/bugs/skip_limit_overflow.js
@@ -8,116 +8,115 @@
* @tags: [do_not_wrap_aggregations_in_facets, assumes_unsharded_collection]
*/
(function() {
- "use strict";
+"use strict";
- load("jstests/libs/analyze_plan.js"); // For 'aggPlanHasStages' and other explain helpers.
+load("jstests/libs/analyze_plan.js"); // For 'aggPlanHasStages' and other explain helpers.
- const coll = db.server39788;
- coll.drop();
+const coll = db.server39788;
+coll.drop();
- function testPipeline(pipeline, expectedResult, optimizedAwayStages) {
- const explainOutput = coll.explain().aggregate(pipeline);
+function testPipeline(pipeline, expectedResult, optimizedAwayStages) {
+ const explainOutput = coll.explain().aggregate(pipeline);
- assert(explainOutput.hasOwnProperty("stages"),
- "Expected pipeline " + tojsononeline(pipeline) +
- " to use an aggregation framework in the explain output: " +
- tojson(explainOutput));
+ assert(explainOutput.hasOwnProperty("stages"),
+ "Expected pipeline " + tojsononeline(pipeline) +
+ " to use an aggregation framework in the explain output: " + tojson(explainOutput));
- if (optimizedAwayStages) {
- optimizedAwayStages.forEach(
- (stage) =>
- assert(!aggPlanHasStage(explainOutput, stage),
- "Expected pipeline " + tojsononeline(pipeline) + " to *not* include a " +
- stage + " stage in the explain output: " + tojson(explainOutput)));
- }
-
- for (let path in expectedResult) {
- const subPaths = path.split(".");
- const stageName = subPaths[0];
- const stages = getAggPlanStages(explainOutput, stageName);
- assert(stages !== null,
- "Expected pipeline " + tojsononeline(pipeline) + " to include a " + stageName +
- " stage in the explain output: " + tojson(explainOutput));
- assert(stages.length == expectedResult[path].length,
- "Expected pipeline " + tojsononeline(pipeline) + " to include " +
- expectedResult[path].length + stageName + " stages in the explain output: " +
- tojson(explainOutput));
- assert.eq(
- stages.reduce(
- (res, stage) => {
- res.push(subPaths.reduce((res, cur) => res[cur], stage));
- return res;
- },
- []),
- expectedResult[path],
- "Stage: " + stageName + ", path: " + path + ", explain: " + tojson(explainOutput));
- }
+ if (optimizedAwayStages) {
+ optimizedAwayStages.forEach(
+ (stage) =>
+ assert(!aggPlanHasStage(explainOutput, stage),
+ "Expected pipeline " + tojsononeline(pipeline) + " to *not* include a " +
+ stage + " stage in the explain output: " + tojson(explainOutput)));
+ }
- // Ensure the aggregate command doesn't fail.
- assert.eq(coll.aggregate(pipeline).toArray(), []);
+ for (let path in expectedResult) {
+ const subPaths = path.split(".");
+ const stageName = subPaths[0];
+ const stages = getAggPlanStages(explainOutput, stageName);
+ assert(stages !== null,
+ "Expected pipeline " + tojsononeline(pipeline) + " to include a " + stageName +
+ " stage in the explain output: " + tojson(explainOutput));
+ assert(stages.length == expectedResult[path].length,
+ "Expected pipeline " + tojsononeline(pipeline) + " to include " +
+ expectedResult[path].length + stageName +
+ " stages in the explain output: " + tojson(explainOutput));
+ assert.eq(
+ stages.reduce(
+ (res, stage) => {
+ res.push(subPaths.reduce((res, cur) => res[cur], stage));
+ return res;
+ },
+ []),
+ expectedResult[path],
+ "Stage: " + stageName + ", path: " + path + ", explain: " + tojson(explainOutput));
}
- // Case where overflow of limit + skip prevents limit stage from being absorbed. Values
- // are specified as integrals > MAX_LONG. Note that we cannot specify this huge value as
- // a NumberLong, as we get a number conversion error (even if it's passed as a string).
- testPipeline([{$sort: {x: -1}}, {$skip: 18446744073709552000}, {$limit: 6}],
- {"$limit": [NumberLong(6)], "$skip": [NumberLong("9223372036854775807")]});
- testPipeline([{$sort: {x: -1}}, {$skip: 6}, {$limit: 18446744073709552000}],
- {"$limit": [NumberLong("9223372036854775807")], "$skip": [NumberLong(6)]});
+ // Ensure the aggregate command doesn't fail.
+ assert.eq(coll.aggregate(pipeline).toArray(), []);
+}
+
+// Case where overflow of limit + skip prevents limit stage from being absorbed. Values
+// are specified as integrals > MAX_LONG. Note that we cannot specify this huge value as
+// a NumberLong, as we get a number conversion error (even if it's passed as a string).
+testPipeline([{$sort: {x: -1}}, {$skip: 18446744073709552000}, {$limit: 6}],
+ {"$limit": [NumberLong(6)], "$skip": [NumberLong("9223372036854775807")]});
+testPipeline([{$sort: {x: -1}}, {$skip: 6}, {$limit: 18446744073709552000}],
+ {"$limit": [NumberLong("9223372036854775807")], "$skip": [NumberLong(6)]});
- // Case where overflow of limit + skip prevents limit stage from being absorbed. One of the
- // values == MAX_LONG, another one is 1.
- testPipeline([{$sort: {x: -1}}, {$skip: NumberLong("9223372036854775807")}, {$limit: 1}],
- {"$limit": [NumberLong(1)], "$skip": [NumberLong("9223372036854775807")]});
- testPipeline([{$sort: {x: -1}}, {$skip: 1}, {$limit: NumberLong("9223372036854775807")}],
- {"$limit": [NumberLong("9223372036854775807")], "$skip": [NumberLong(1)]});
+// Case where overflow of limit + skip prevents limit stage from being absorbed. One of the
+// values == MAX_LONG, another one is 1.
+testPipeline([{$sort: {x: -1}}, {$skip: NumberLong("9223372036854775807")}, {$limit: 1}],
+ {"$limit": [NumberLong(1)], "$skip": [NumberLong("9223372036854775807")]});
+testPipeline([{$sort: {x: -1}}, {$skip: 1}, {$limit: NumberLong("9223372036854775807")}],
+ {"$limit": [NumberLong("9223372036854775807")], "$skip": [NumberLong(1)]});
- // Case where limit + skip do not overflow. Limit == MAX_LONG and skip is 0. Should be able to
- // absorb the limit and skip stages.
- // Note that we cannot specify limit == 0, so we expect an error in this case.
- testPipeline([{$sort: {x: -1}}, {$skip: 0}, {$limit: NumberLong("9223372036854775807")}],
- {"$cursor.limit": [NumberLong("9223372036854775807")]},
- ["$skip", "$limit"]);
+// Case where limit + skip do not overflow. Limit == MAX_LONG and skip is 0. Should be able to
+// absorb the limit and skip stages.
+// Note that we cannot specify limit == 0, so we expect an error in this case.
+testPipeline([{$sort: {x: -1}}, {$skip: 0}, {$limit: NumberLong("9223372036854775807")}],
+ {"$cursor.limit": [NumberLong("9223372036854775807")]},
+ ["$skip", "$limit"]);
- // Case where limit + skip do not overflow. One value is MAX_LONG - 1 and another one is 1.
- // Should be able to absorb the limit stage.
- testPipeline([{$sort: {x: -1}}, {$skip: NumberLong("9223372036854775806")}, {$limit: 1}],
- {
- "$cursor.limit": [NumberLong("9223372036854775807")],
- "$skip": [NumberLong("9223372036854775806")]
- },
- ["$limit"]);
- testPipeline([{$sort: {x: -1}}, {$skip: 1}, {$limit: NumberLong("9223372036854775806")}],
- {"$cursor.limit": [NumberLong("9223372036854775807")], "$skip": [NumberLong(1)]},
- ["$limit"]);
+// Case where limit + skip do not overflow. One value is MAX_LONG - 1 and another one is 1.
+// Should be able to absorb the limit stage.
+testPipeline([{$sort: {x: -1}}, {$skip: NumberLong("9223372036854775806")}, {$limit: 1}],
+ {
+ "$cursor.limit": [NumberLong("9223372036854775807")],
+ "$skip": [NumberLong("9223372036854775806")]
+ },
+ ["$limit"]);
+testPipeline([{$sort: {x: -1}}, {$skip: 1}, {$limit: NumberLong("9223372036854775806")}],
+ {"$cursor.limit": [NumberLong("9223372036854775807")], "$skip": [NumberLong(1)]},
+ ["$limit"]);
- // Case where limit + skip do not overflow. Both values are < MAX_LONG.
- testPipeline([{$sort: {x: -1}}, {$skip: 674761616283}, {$limit: 35361718}],
- {"$cursor.limit": [NumberLong(674796978001)], "$skip": [NumberLong(674761616283)]},
- ["$limit"]);
- testPipeline([{$sort: {x: -1}}, {$skip: 35361718}, {$limit: 674761616283}],
- {"$cursor.limit": [NumberLong(674796978001)], "$skip": [NumberLong(35361718)]},
- ["$limit"]);
+// Case where limit + skip do not overflow. Both values are < MAX_LONG.
+testPipeline([{$sort: {x: -1}}, {$skip: 674761616283}, {$limit: 35361718}],
+ {"$cursor.limit": [NumberLong(674796978001)], "$skip": [NumberLong(674761616283)]},
+ ["$limit"]);
+testPipeline([{$sort: {x: -1}}, {$skip: 35361718}, {$limit: 674761616283}],
+ {"$cursor.limit": [NumberLong(674796978001)], "$skip": [NumberLong(35361718)]},
+ ["$limit"]);
- // Case where where overflow of limit + skip + skip prevents limit stage from being absorbed.
- // One skip == MAX_LONG - 1, another one is 1. Should merge two skip stages into one.
- testPipeline(
- [{$sort: {x: -1}}, {$skip: 1}, {$skip: NumberLong("9223372036854775806")}, {$limit: 1}],
- {"$limit": [NumberLong(1)], "$skip": [NumberLong("9223372036854775807")]});
+// Case where where overflow of limit + skip + skip prevents limit stage from being absorbed.
+// One skip == MAX_LONG - 1, another one is 1. Should merge two skip stages into one.
+testPipeline(
+ [{$sort: {x: -1}}, {$skip: 1}, {$skip: NumberLong("9223372036854775806")}, {$limit: 1}],
+ {"$limit": [NumberLong(1)], "$skip": [NumberLong("9223372036854775807")]});
- // Case where where overflow of limit + skip + skip prevents limit stage from being absorbed.
- // One skip == MAX_LONG, another one is 1. Should not absorb or merge any stages.
- testPipeline(
- [{$sort: {x: -1}}, {$skip: 1}, {$skip: NumberLong("9223372036854775807")}, {$limit: 1}],
- {"$limit": [NumberLong(1)], "$skip": [NumberLong(1), NumberLong("9223372036854775807")]});
+// Case where where overflow of limit + skip + skip prevents limit stage from being absorbed.
+// One skip == MAX_LONG, another one is 1. Should not absorb or merge any stages.
+testPipeline(
+ [{$sort: {x: -1}}, {$skip: 1}, {$skip: NumberLong("9223372036854775807")}, {$limit: 1}],
+ {"$limit": [NumberLong(1)], "$skip": [NumberLong(1), NumberLong("9223372036854775807")]});
- // Case where sample size is > MAX_LONG.
- testPipeline([{$sample: {size: 18446744073709552000}}],
- {"$sample.size": [NumberLong("9223372036854775807")]});
- // Case where sample size is == MAX_LONG.
- testPipeline([{$sample: {size: NumberLong("9223372036854775807")}}],
- {"$sample.size": [NumberLong("9223372036854775807")]});
- // Case where sample size is == MAX_LONG - 1.
- testPipeline([{$sample: {size: NumberLong("9223372036854775806")}}],
- {"$sample.size": [NumberLong("9223372036854775806")]});
+// Case where sample size is > MAX_LONG.
+testPipeline([{$sample: {size: 18446744073709552000}}],
+ {"$sample.size": [NumberLong("9223372036854775807")]});
+// Case where sample size is == MAX_LONG.
+testPipeline([{$sample: {size: NumberLong("9223372036854775807")}}],
+ {"$sample.size": [NumberLong("9223372036854775807")]});
+// Case where sample size is == MAX_LONG - 1.
+testPipeline([{$sample: {size: NumberLong("9223372036854775806")}}],
+ {"$sample.size": [NumberLong("9223372036854775806")]});
})();
diff --git a/jstests/aggregation/bugs/sort_arrays.js b/jstests/aggregation/bugs/sort_arrays.js
index 9fbb707decb..e83b4466cc6 100644
--- a/jstests/aggregation/bugs/sort_arrays.js
+++ b/jstests/aggregation/bugs/sort_arrays.js
@@ -1,17 +1,17 @@
// Tests that sorting by a field that contains an array will sort by the minimum element in that
// array.
(function() {
- "use strict";
+"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]}];
+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, _id: 1}}]).toArray(), expectedOrder);
- assert.eq(coll.find().sort({a: 1, _id: 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, _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, _id: 1}}]).toArray(), expectedOrder);
+assert.eq(coll.find().sort({a: 1, _id: 1}).toArray(), expectedOrder);
}());
diff --git a/jstests/aggregation/bugs/substr.js b/jstests/aggregation/bugs/substr.js
index 1090b09dffb..c4eaff7e137 100644
--- a/jstests/aggregation/bugs/substr.js
+++ b/jstests/aggregation/bugs/substr.js
@@ -122,8 +122,8 @@ assert.eq(
a: {
$substrBytes: [
{
- $substrBytes:
- [{$substrBytes: [{$substrBytes: ['abcdefghij', 1, 6]}, 2, 5]}, 0, 3]
+ $substrBytes:
+ [{$substrBytes: [{$substrBytes: ['abcdefghij', 1, 6]}, 2, 5]}, 0, 3]
},
1,
1