summaryrefslogtreecommitdiff
path: root/jstests/core
diff options
context:
space:
mode:
authorCharlie Swanson <charlie.swanson@mongodb.com>2018-01-11 14:00:27 -0500
committerCharlie Swanson <charlie.swanson@mongodb.com>2018-01-19 09:55:59 -0500
commit87c9442cc30d4101693bb8ccb6fd4509aa048558 (patch)
tree99ab7b36d89776693c09f271e4de4fd4f64846e3 /jstests/core
parent71ae3ed5b7e99ddb629ec64b85f4bd75b73aff17 (diff)
downloadmongo-87c9442cc30d4101693bb8ccb6fd4509aa048558.tar.gz
SERVER-31785 Use 2 shards in sharded jscore passthrough.
Diffstat (limited to 'jstests/core')
-rw-r--r--jstests/core/batch_size.js235
-rw-r--r--jstests/core/bindata_indexonly.js10
-rw-r--r--jstests/core/bittest.js4
-rw-r--r--jstests/core/collation.js48
-rw-r--r--jstests/core/coveredIndex1.js4
-rw-r--r--jstests/core/coveredIndex2.js9
-rw-r--r--jstests/core/covered_index_compound_1.js14
-rw-r--r--jstests/core/covered_index_negative_1.js12
-rw-r--r--jstests/core/covered_index_simple_1.js14
-rw-r--r--jstests/core/covered_index_simple_2.js12
-rw-r--r--jstests/core/covered_index_simple_3.js16
-rw-r--r--jstests/core/covered_index_simple_id.js12
-rw-r--r--jstests/core/covered_index_sort_1.js6
-rw-r--r--jstests/core/covered_index_sort_2.js2
-rw-r--r--jstests/core/covered_index_sort_3.js2
-rw-r--r--jstests/core/covered_multikey.js22
-rw-r--r--jstests/core/distinct_array1.js44
-rw-r--r--jstests/core/distinct_compound_index.js17
-rw-r--r--jstests/core/distinct_index1.js38
-rw-r--r--jstests/core/distinct_multikey.js44
-rw-r--r--jstests/core/explain2.js3
-rw-r--r--jstests/core/explain_count.js18
-rw-r--r--jstests/core/explain_delete.js14
-rw-r--r--jstests/core/explain_distinct.js18
-rw-r--r--jstests/core/explain_execution_error.js58
-rw-r--r--jstests/core/explain_multikey.js7
-rw-r--r--jstests/core/explain_shell_helpers.js38
-rw-r--r--jstests/core/find1.js4
-rw-r--r--jstests/core/find5.js2
-rw-r--r--jstests/core/fts_mix.js20
-rw-r--r--jstests/core/fts_projection.js4
-rw-r--r--jstests/core/getmore_invalidated_cursors.js7
-rw-r--r--jstests/core/hashindex1.js10
-rw-r--r--jstests/core/idhack.js8
-rw-r--r--jstests/core/indexOtherNamespace.js4
-rw-r--r--jstests/core/index_bounds_pipe.js18
-rw-r--r--jstests/core/index_bounds_timestamp.js46
-rw-r--r--jstests/core/index_check2.js6
-rw-r--r--jstests/core/index_check6.js4
-rw-r--r--jstests/core/index_decimal.js2
-rw-r--r--jstests/core/index_diag.js33
-rw-r--r--jstests/core/index_elemmatch2.js2
-rw-r--r--jstests/core/index_filter_commands.js6
-rw-r--r--jstests/core/index_partial_read_ops.js22
-rw-r--r--jstests/core/index_type_change.js2
-rw-r--r--jstests/core/indexj.js3
-rw-r--r--jstests/core/maxscan.js18
-rw-r--r--jstests/core/min_max_bounds.js26
-rw-r--r--jstests/core/minmax.js22
-rw-r--r--jstests/core/mr5.js110
-rw-r--r--jstests/core/mr_stored.js4
-rw-r--r--jstests/core/or2.js4
-rw-r--r--jstests/core/or3.js2
-rw-r--r--jstests/core/ord.js27
-rw-r--r--jstests/core/proj_key1.js7
-rw-r--r--jstests/core/projection_dotted_paths.js34
-rw-r--r--jstests/core/record_store_count.js12
-rw-r--r--jstests/core/regex6.js3
-rw-r--r--jstests/core/return_key.js12
-rw-r--r--jstests/core/set_type_change.js3
-rw-r--r--jstests/core/snapshot_queries.js6
-rw-r--r--jstests/core/sort_array.js6
-rw-r--r--jstests/core/text_covered_matching.js12
-rw-r--r--jstests/core/ts1.js82
-rw-r--r--jstests/core/updatej.js8
-rw-r--r--jstests/core/where4.js6
66 files changed, 748 insertions, 580 deletions
diff --git a/jstests/core/batch_size.js b/jstests/core/batch_size.js
index b715f936052..cdd60e77cd2 100644
--- a/jstests/core/batch_size.js
+++ b/jstests/core/batch_size.js
@@ -2,113 +2,128 @@
// Test subtleties of batchSize and limit.
-var t = db.jstests_batch_size;
-t.drop();
-
-for (var i = 0; i < 4; i++) {
- t.save({_id: i, a: i});
-}
-
-function runIndexedTests() {
- // With limit, indexed.
- assert.eq(2, t.find().limit(2).itcount(), 'G');
- assert.eq(2, t.find().sort({a: 1}).limit(2).itcount(), 'H');
-
- // With batchSize, indexed.
- // SERVER-12438: If there is an index that provides the sort,
- // then a plan with an unindexed sort should never be used.
- // Consequently, batchSize will NOT be a hard limit in this case.
- // WARNING: the behavior described above may change in the future.
- assert.eq(4, t.find().batchSize(2).itcount(), 'I');
- assert.eq(4, t.find().sort({a: 1}).batchSize(2).itcount(), 'J');
-}
-
-// Without batch size or limit, unindexed.
-assert.eq(4, t.find().itcount(), 'A');
-assert.eq(4, t.find().sort({a: 1}).itcount(), 'B');
-
-// With limit, unindexed.
-assert.eq(2, t.find().limit(2).itcount(), 'C');
-assert.eq(2, t.find().sort({a: 1}).limit(2).itcount(), 'D');
-
-assert.eq(4, t.find().batchSize(2).itcount(), 'E');
-assert.eq(4, t.find().sort({a: 1}).batchSize(2).itcount(), 'F');
-
-// With negative batchSize. A negative batchSize value instructs the server
-// to return just a single batch of results.
-assert.eq(1, t.find().batchSize(-1).itcount(), 'G');
-assert.eq(2, t.find().batchSize(-2).itcount(), 'H');
-
-// Run the tests with the index twice in order to double check plan caching.
-t.ensureIndex({a: 1});
-for (var i = 0; i < 2; i++) {
- runIndexedTests();
-}
-
-// The next tests make sure that we obey limit and batchSize properly when
-// the sort could be either indexed or unindexed.
-t.drop();
-t.ensureIndex({a: 1});
-t.ensureIndex({b: 1});
-
-for (var i = 0; i < 100; i++) {
- t.save({_id: i, a: i, b: 1});
-}
-
-// Without a hint. Do it twice to make sure caching is ok.
-for (var i = 0; i < 2; i++) {
- assert.eq(15, t.find({a: {$gte: 85}}).sort({b: 1}).batchSize(2).itcount(), 'K');
- assert.eq(6, t.find({a: {$gte: 85}}).sort({b: 1}).limit(6).itcount(), 'L');
-}
-
-// Hinting 'a'.
-assert.eq(15, t.find({a: {$gte: 85}}).sort({b: 1}).hint({a: 1}).batchSize(2).itcount(), 'M');
-assert.eq(6, t.find({a: {$gte: 85}}).sort({b: 1}).hint({a: 1}).limit(6).itcount(), 'N');
-
-// Hinting 'b'.
-assert.eq(15, t.find({a: {$gte: 85}}).sort({b: 1}).hint({b: 1}).batchSize(2).itcount(), 'O');
-assert.eq(6, t.find({a: {$gte: 85}}).sort({b: 1}).hint({b: 1}).limit(6).itcount(), 'P');
-
-// With explain.
-var explain = t.find({a: {$gte: 85}}).sort({b: 1}).batchSize(2).explain("executionStats");
-assert.eq(15, explain.executionStats.nReturned, 'Q');
-explain = t.find({a: {$gte: 85}}).sort({b: 1}).limit(6).explain("executionStats");
-assert.eq(6, explain.executionStats.nReturned, 'R');
-
-// Double check that we're not scanning more stuff than we have to.
-// In order to get the sort using index 'a', we should need to scan
-// about 50 keys and 50 documents.
-var explain = t.find({a: {$gte: 50}}).sort({b: 1}).hint({a: 1}).limit(6).explain("executionStats");
-assert.lte(explain.executionStats.totalKeysExamined, 60, 'S');
-assert.lte(explain.executionStats.totalDocsExamined, 60, 'T');
-assert.eq(explain.executionStats.nReturned, 6, 'U');
-
-// -------
-
-// During plan ranking, we treat ntoreturn as a limit. This prevents us from buffering
-// too much data in a blocking sort stage during plan ranking.
-t.drop();
-
-// Generate big string to use in the object - 1MB+ String
-var bigStr = "ABCDEFGHIJKLMNBOPQRSTUVWXYZ012345687890";
-while (bigStr.length < 1000000) {
- bigStr = bigStr + "::" + bigStr;
-}
-
-// Insert enough documents to exceed the 32 MB in-memory sort limit.
-for (var i = 0; i < 40; i++) {
- var doc = {x: 1, y: 1, z: i, big: bigStr};
- t.insert(doc);
-}
-
-// Two indices needed in order to trigger plan ranking. Neither index provides
-// the sort order.
-t.ensureIndex({x: 1});
-t.ensureIndex({y: 1});
-
-// We should only buffer 3 docs in memory.
-var cursor = t.find({x: 1, y: 1}).sort({z: -1}).limit(3);
-assert.eq(39, cursor.next()["z"]);
-assert.eq(38, cursor.next()["z"]);
-assert.eq(37, cursor.next()["z"]);
-assert(!cursor.hasNext());
+(function() {
+ "use strict";
+ load("jstests/libs/fixture_helpers.js"); // For FixtureHelpers.
+ var t = db.jstests_batch_size;
+ t.drop();
+
+ for (var i = 0; i < 4; i++) {
+ t.save({_id: i, a: i});
+ }
+
+ function runIndexedTests() {
+ // With limit, indexed.
+ assert.eq(2, t.find().limit(2).itcount());
+ assert.eq(2, t.find().sort({a: 1}).limit(2).itcount());
+
+ // With batchSize, indexed.
+ // SERVER-12438: If there is an index that provides the sort, then a plan with an unindexed
+ // sort should never be used. Consequently, batchSize will NOT be a hard limit in this
+ // case. WARNING: the behavior described above may change in the future.
+ assert.eq(4, t.find().batchSize(2).itcount());
+ assert.eq(4, t.find().sort({a: 1}).batchSize(2).itcount());
+ }
+
+ // Without batch size or limit, unindexed.
+ assert.eq(4, t.find().itcount());
+ assert.eq(4, t.find().sort({a: 1}).itcount());
+
+ // With limit, unindexed.
+ assert.eq(2, t.find().limit(2).itcount());
+ assert.eq(2, t.find().sort({a: 1}).limit(2).itcount());
+
+ assert.eq(4, t.find().batchSize(2).itcount());
+ assert.eq(4, t.find().sort({a: 1}).batchSize(2).itcount());
+
+ // With negative batchSize. A negative batchSize value instructs the server
+ // to return just a single batch of results.
+ assert.eq(1, t.find().batchSize(-1).itcount());
+ assert.eq(2, t.find().batchSize(-2).itcount());
+
+ // Run the tests with the index twice in order to double check plan caching.
+ t.ensureIndex({a: 1});
+ for (var i = 0; i < 2; i++) {
+ runIndexedTests();
+ }
+
+ // The next tests make sure that we obey limit and batchSize properly when the sort could be
+ // either indexed or unindexed.
+ t.drop();
+ t.ensureIndex({a: 1});
+ t.ensureIndex({b: 1});
+
+ for (var i = 0; i < 100; i++) {
+ t.save({_id: i, a: i, b: 1});
+ }
+
+ // Without a hint. Do it twice to make sure caching is ok.
+ for (var i = 0; i < 2; i++) {
+ assert.eq(15, t.find({a: {$gte: 85}}).sort({b: 1}).batchSize(2).itcount());
+ assert.eq(6, t.find({a: {$gte: 85}}).sort({b: 1}).limit(6).itcount());
+ }
+
+ // Hinting 'a'.
+ assert.eq(15, t.find({a: {$gte: 85}}).sort({b: 1}).hint({a: 1}).batchSize(2).itcount());
+ assert.eq(6, t.find({a: {$gte: 85}}).sort({b: 1}).hint({a: 1}).limit(6).itcount());
+
+ // Hinting 'b'.
+ assert.eq(15, t.find({a: {$gte: 85}}).sort({b: 1}).hint({b: 1}).batchSize(2).itcount());
+ assert.eq(6, t.find({a: {$gte: 85}}).sort({b: 1}).hint({b: 1}).limit(6).itcount());
+
+ // With explain.
+ var explain = t.find({a: {$gte: 85}}).sort({b: 1}).batchSize(2).explain("executionStats");
+ assert.eq(15, explain.executionStats.nReturned);
+ explain = t.find({a: {$gte: 85}}).sort({b: 1}).limit(6).explain("executionStats");
+ if (FixtureHelpers.isMongos(db)) {
+ // If we're talking to a mongos, we expect at most one batch from each shard.
+ assert.eq(FixtureHelpers.numberOfShardsForCollection(t) * 6,
+ explain.executionStats.nReturned);
+ } else {
+ assert.eq(6, explain.executionStats.nReturned);
+ }
+
+ // Double check that we're not scanning more stuff than we have to. In order to get the sort
+ // using index 'a', we should need to scan about 50 keys and 50 documents.
+ var explain =
+ t.find({a: {$gte: 50}}).sort({b: 1}).hint({a: 1}).limit(6).explain("executionStats");
+ assert.lte(explain.executionStats.totalKeysExamined, 60);
+ assert.lte(explain.executionStats.totalDocsExamined, 60);
+ if (FixtureHelpers.isMongos(db)) {
+ // If we're talking to a mongos, we expect at most one batch from each shard.
+ assert.eq(FixtureHelpers.numberOfShardsForCollection(t) * 6,
+ explain.executionStats.nReturned);
+ } else {
+ assert.eq(6, explain.executionStats.nReturned);
+ }
+
+ // -------
+
+ // During plan ranking, we treat ntoreturn as a limit. This prevents us from buffering too much
+ // data in a blocking sort stage during plan ranking.
+ t.drop();
+
+ // Generate big string to use in the object - 1MB+ String
+ var bigStr = "ABCDEFGHIJKLMNBOPQRSTUVWXYZ012345687890";
+ while (bigStr.length < 1000000) {
+ bigStr = bigStr + "::" + bigStr;
+ }
+
+ // Insert enough documents to exceed the 32 MB in-memory sort limit.
+ const nDocs = 40 * FixtureHelpers.numberOfShardsForCollection(t);
+ for (var i = 0; i < nDocs; i++) {
+ var doc = {x: 1, y: 1, z: i, big: bigStr};
+ t.insert(doc);
+ }
+
+ // Two indices needed in order to trigger plan ranking. Neither index provides the sort order.
+ t.ensureIndex({x: 1});
+ t.ensureIndex({y: 1});
+
+ // We should only buffer 3 docs in memory.
+ var cursor = t.find({x: 1, y: 1}).sort({z: -1}).limit(3);
+ assert.eq(nDocs - 1, cursor.next().z);
+ assert.eq(nDocs - 2, cursor.next().z);
+ assert.eq(nDocs - 3, cursor.next().z);
+ assert(!cursor.hasNext());
+}());
diff --git a/jstests/core/bindata_indexonly.js b/jstests/core/bindata_indexonly.js
index d8f8bf931b9..4eb24476010 100644
--- a/jstests/core/bindata_indexonly.js
+++ b/jstests/core/bindata_indexonly.js
@@ -28,7 +28,7 @@
.hint({_id: 1, a: 1})
.explain("executionStats");
- assert(isIndexOnly(explain.queryPlanner.winningPlan),
+ assert(isIndexOnly(db, explain.queryPlanner.winningPlan),
"indexonly.BinData(0, " + blob + ") - must be index-only");
assert.eq(1,
explain.executionStats.nReturned,
@@ -45,7 +45,7 @@
explain = coll.find({_id: {$lt: BinData(0, "AAAAAAAAAAAAAAAAAAAAAAAAAAAA")}}, {_id: 1, a: 1})
.hint({_id: 1, a: 1})
.explain("executionStats");
- assert(isIndexOnly(explain), "indexonly.$lt.1 - must be index-only");
+ assert(isIndexOnly(db, explain), "indexonly.$lt.1 - must be index-only");
assert.eq(0,
explain.executionStats.nReturned,
"correctcount.$lt.1 - not returning correct documents");
@@ -53,7 +53,7 @@
explain = coll.find({_id: {$gt: BinData(0, "////////////////////////////")}}, {_id: 1, a: 1})
.hint({_id: 1, a: 1})
.explain("executionStats");
- assert(isIndexOnly(explain), "indexonly.$gt.2 - must be index-only");
+ assert(isIndexOnly(db, explain), "indexonly.$gt.2 - must be index-only");
assert.eq(0,
explain.executionStats.nReturned,
"correctcount.$gt.2 - not returning correct documents");
@@ -61,7 +61,7 @@
explain = coll.find({_id: {$lte: BinData(0, "AQAAAAEBAAVlbl9VSwAAAAAAAAhv")}}, {_id: 1, a: 1})
.hint({_id: 1, a: 1})
.explain("executionStats");
- assert(isIndexOnly(explain), "indexonly.$lte.3 - must be index-only");
+ assert(isIndexOnly(db, explain), "indexonly.$lte.3 - must be index-only");
assert.eq(2,
explain.executionStats.nReturned,
"correctcount.$lte.3 - not returning correct documents");
@@ -69,7 +69,7 @@
explain = coll.find({_id: {$gte: BinData(0, "AQAAAAEBAAVlbl9VSwAAAAAAAAhz")}}, {_id: 1, a: 1})
.hint({_id: 1, a: 1})
.explain("executionStats");
- assert(isIndexOnly(explain), "indexonly.$gte.3 - must be index-only");
+ assert(isIndexOnly(db, explain), "indexonly.$gte.3 - must be index-only");
assert.eq(2,
explain.executionStats.nReturned,
"correctcount.$gte.3 - not returning correct documents");
diff --git a/jstests/core/bittest.js b/jstests/core/bittest.js
index 0a54215ee60..194bf3df048 100644
--- a/jstests/core/bittest.js
+++ b/jstests/core/bittest.js
@@ -10,7 +10,7 @@
function assertQueryCorrect(query, count) {
var explain = coll.find(query).explain("executionStats");
- assert(isCollscan(explain.queryPlanner.winningPlan),
+ assert(isCollscan(db, explain.queryPlanner.winningPlan),
"expected bit test query plan to be COLLSCAN");
assert.eq(count,
explain.executionStats.nReturned,
@@ -153,4 +153,4 @@
1);
coll.drop();
-})(); \ No newline at end of file
+})();
diff --git a/jstests/core/collation.js b/jstests/core/collation.js
index 0e6b4974af4..dbc0bd3307a 100644
--- a/jstests/core/collation.js
+++ b/jstests/core/collation.js
@@ -258,17 +258,17 @@
// Query has simple collation, but index has fr_CA collation.
explainRes = coll.find({a: "foo"}).explain();
assert.commandWorked(explainRes);
- assert(planHasStage(explainRes.queryPlanner.winningPlan, "COLLSCAN"));
+ assert(planHasStage(db, explainRes.queryPlanner.winningPlan, "COLLSCAN"));
// Query has en_US collation, but index has fr_CA collation.
explainRes = coll.find({a: "foo"}).collation({locale: "en_US"}).explain();
assert.commandWorked(explainRes);
- assert(planHasStage(explainRes.queryPlanner.winningPlan, "COLLSCAN"));
+ assert(planHasStage(db, explainRes.queryPlanner.winningPlan, "COLLSCAN"));
// Matching collations.
explainRes = coll.find({a: "foo"}).collation({locale: "fr_CA"}).explain();
assert.commandWorked(explainRes);
- assert(planHasStage(explainRes.queryPlanner.winningPlan, "IXSCAN"));
+ assert(planHasStage(db, explainRes.queryPlanner.winningPlan, "IXSCAN"));
}
// Should not be possible to create a text index with an explicit non-simple collation.
@@ -327,7 +327,7 @@
assert.commandWorked(db.createCollection(coll.getName(), {collation: {locale: "en_US"}}));
assert.commandWorked(coll.ensureIndex({a: 1}, {collation: {locale: "en_US"}}));
var explain = coll.explain("queryPlanner").aggregate([{$match: {a: "foo"}}]).stages[0].$cursor;
- assert(isIxscan(explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, explain.queryPlanner.winningPlan));
// Aggregation should not use index when no collation specified and collection default
// collation is incompatible with index collation.
@@ -335,7 +335,7 @@
assert.commandWorked(db.createCollection(coll.getName(), {collation: {locale: "en_US"}}));
assert.commandWorked(coll.ensureIndex({a: 1}, {collation: {locale: "simple"}}));
var explain = coll.explain("queryPlanner").aggregate([{$match: {a: "foo"}}]).stages[0].$cursor;
- assert(isCollscan(explain.queryPlanner.winningPlan));
+ assert(isCollscan(db, explain.queryPlanner.winningPlan));
// Explain of aggregation with collation should succeed.
assert.commandWorked(coll.explain().aggregate([], {collation: {locale: "fr"}}));
@@ -442,8 +442,8 @@
assert.commandWorked(coll.createIndex({a: 1}));
explainRes = coll.explain("executionStats").find({a: "foo"}).count();
assert.commandWorked(explainRes);
- assert(planHasStage(explainRes.executionStats.executionStages, "COUNT_SCAN"));
- assert(!planHasStage(explainRes.executionStats.executionStages, "FETCH"));
+ assert(planHasStage(db, explainRes.executionStats.executionStages, "COUNT_SCAN"));
+ assert(!planHasStage(db, explainRes.executionStats.executionStages, "FETCH"));
//
// Collation tests for distinct.
@@ -498,28 +498,28 @@
assert.commandWorked(db.createCollection(coll.getName(), {collation: {locale: "en_US"}}));
assert.commandWorked(coll.ensureIndex({a: 1}, {collation: {locale: "en_US"}}));
var explain = coll.explain("queryPlanner").distinct("a");
- assert(planHasStage(explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
- assert(planHasStage(explain.queryPlanner.winningPlan, "FETCH"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "FETCH"));
// Distinct scan on strings can be used over an index with a collation when the predicate has
// exact bounds.
explain = coll.explain("queryPlanner").distinct("a", {a: {$gt: "foo"}});
- assert(planHasStage(explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
- assert(planHasStage(explain.queryPlanner.winningPlan, "FETCH"));
- assert(!planHasStage(explain.queryPlanner.winningPlan, "PROJECTION"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "FETCH"));
+ assert(!planHasStage(db, explain.queryPlanner.winningPlan, "PROJECTION"));
// Distinct scan cannot be used over an index with a collation when the predicate has inexact
// bounds.
explain = coll.explain("queryPlanner").distinct("a", {a: {$exists: true}});
- assert(planHasStage(explain.queryPlanner.winningPlan, "IXSCAN"));
- assert(planHasStage(explain.queryPlanner.winningPlan, "FETCH"));
- assert(!planHasStage(explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "IXSCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "FETCH"));
+ assert(!planHasStage(db, explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
// Distinct scan can be used without a fetch when predicate has exact non-string bounds.
explain = coll.explain("queryPlanner").distinct("a", {a: {$gt: 3}});
- assert(planHasStage(explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
- assert(planHasStage(explain.queryPlanner.winningPlan, "PROJECTION"));
- assert(!planHasStage(explain.queryPlanner.winningPlan, "FETCH"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "PROJECTION"));
+ assert(!planHasStage(db, explain.queryPlanner.winningPlan, "FETCH"));
// Distinct should not use index when no collation specified and collection default collation is
// incompatible with index collation.
@@ -527,7 +527,7 @@
assert.commandWorked(db.createCollection(coll.getName(), {collation: {locale: "en_US"}}));
assert.commandWorked(coll.ensureIndex({a: 1}, {collation: {locale: "simple"}}));
var explain = coll.explain("queryPlanner").distinct("a");
- assert(isCollscan(explain.queryPlanner.winningPlan));
+ assert(isCollscan(db, explain.queryPlanner.winningPlan));
// Explain of DISTINCT_SCAN stage should include index collation.
coll.drop();
@@ -779,7 +779,7 @@
assert.commandWorked(db.createCollection(coll.getName(), {collation: {locale: "en_US"}}));
assert.commandWorked(coll.ensureIndex({a: 1}, {collation: {locale: "en_US"}}));
var explain = coll.find({a: "foo"}).explain("queryPlanner");
- assert(isIxscan(explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, explain.queryPlanner.winningPlan));
// Find should select compatible index when no collation specified and collection default
// collation is "simple".
@@ -787,7 +787,7 @@
assert.commandWorked(db.createCollection(coll.getName(), {collation: {locale: "simple"}}));
assert.commandWorked(coll.ensureIndex({a: 1}, {collation: {locale: "simple"}}));
var explain = coll.find({a: "foo"}).explain("queryPlanner");
- assert(isIxscan(explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, explain.queryPlanner.winningPlan));
// Find should not use index when no collation specified, index collation is "simple", and
// collection has a non-"simple" default collation.
@@ -795,7 +795,7 @@
assert.commandWorked(db.createCollection(coll.getName(), {collation: {locale: "en_US"}}));
assert.commandWorked(coll.ensureIndex({a: 1}, {collation: {locale: "simple"}}));
var explain = coll.find({a: "foo"}).explain("queryPlanner");
- assert(isCollscan(explain.queryPlanner.winningPlan));
+ assert(isCollscan(db, explain.queryPlanner.winningPlan));
// Find should select compatible index when "simple" collation specified and collection has a
// non-"simple" default collation.
@@ -803,7 +803,7 @@
assert.commandWorked(db.createCollection(coll.getName(), {collation: {locale: "en_US"}}));
assert.commandWorked(coll.ensureIndex({a: 1}, {collation: {locale: "simple"}}));
var explain = coll.find({a: "foo"}).collation({locale: "simple"}).explain("queryPlanner");
- assert(isIxscan(explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, explain.queryPlanner.winningPlan));
// Find should return correct results when collation specified and run with explain.
coll.drop();
@@ -2150,7 +2150,7 @@
.sort({a: 1, b: 1})
.explain();
assert.commandWorked(explainRes);
- assert(planHasStage(explainRes.queryPlanner.winningPlan, "SORT"));
+ assert(planHasStage(db, explainRes.queryPlanner.winningPlan, "SORT"));
// This query should fail since min has a string as one of it's boundaries, and the
// collation doesn't match that of the index.
diff --git a/jstests/core/coveredIndex1.js b/jstests/core/coveredIndex1.js
index 9e6c892567e..7776a48c014 100644
--- a/jstests/core/coveredIndex1.js
+++ b/jstests/core/coveredIndex1.js
@@ -40,11 +40,11 @@
assert(explain.queryPlanner.hasOwnProperty("winningPlan"), tojson(explain));
const winningPlan = explain.queryPlanner.winningPlan;
if (isCovered) {
- assert(isIndexOnly(winningPlan),
+ assert(isIndexOnly(db, winningPlan),
"Query " + tojson(query) + " with projection " + tojson(projection) +
" should have been covered, but got this plan: " + tojson(winningPlan));
} else {
- assert(!isIndexOnly(winningPlan),
+ assert(!isIndexOnly(db, winningPlan),
"Query " + tojson(query) + " with projection " + tojson(projection) +
" should not have been covered, but got this plan: " + tojson(winningPlan));
}
diff --git a/jstests/core/coveredIndex2.js b/jstests/core/coveredIndex2.js
index 058b739fba2..7f9983618fc 100644
--- a/jstests/core/coveredIndex2.js
+++ b/jstests/core/coveredIndex2.js
@@ -17,15 +17,16 @@ assert.eq(t.count(), 2, "Not right length");
// use simple index
t.ensureIndex({a: 1});
var plan = t.find({a: 1}).explain();
-assert(!isIndexOnly(plan.queryPlanner.winningPlan),
+assert(!isIndexOnly(db, plan.queryPlanner.winningPlan),
"Find using covered index but all fields are returned");
var plan = t.find({a: 1}, {a: 1}).explain();
-assert(!isIndexOnly(plan.queryPlanner.winningPlan), "Find using covered index but _id is returned");
+assert(!isIndexOnly(db, plan.queryPlanner.winningPlan),
+ "Find using covered index but _id is returned");
var plan = t.find({a: 1}, {a: 1, _id: 0}).explain();
-assert(isIndexOnly(plan.queryPlanner.winningPlan), "Find is not using covered index");
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan), "Find is not using covered index");
// add multikey
t.save({a: [3, 4]});
var plan = t.find({a: 1}, {a: 1, _id: 0}).explain();
-assert(!isIndexOnly(plan.queryPlanner.winningPlan),
+assert(!isIndexOnly(db, plan.queryPlanner.winningPlan),
"Find is using covered index even after multikey insert");
diff --git a/jstests/core/covered_index_compound_1.js b/jstests/core/covered_index_compound_1.js
index ba2c9b6ecc5..79b015220b5 100644
--- a/jstests/core/covered_index_compound_1.js
+++ b/jstests/core/covered_index_compound_1.js
@@ -19,7 +19,7 @@ coll.ensureIndex({a: 1, b: -1, c: 1});
var plan = coll.find({a: 10, b: "strvar_10", c: 0}, {a: 1, b: 1, c: 1, _id: 0})
.hint({a: 1, b: -1, c: 1})
.explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"compound.1.1 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -29,7 +29,7 @@ assert.eq(0,
var plan = coll.find({a: 26, b: "strvar_0"}, {a: 1, b: 1, c: 1, _id: 0})
.hint({a: 1, b: -1, c: 1})
.explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"compound.1.2 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -39,7 +39,7 @@ assert.eq(0,
var plan = coll.find({a: 38, b: "strvar_12", c: 8}, {b: 1, c: 1, _id: 0})
.hint({a: 1, b: -1, c: 1})
.explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"compound.1.3 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -47,7 +47,7 @@ assert.eq(0,
// Test no query
var plan = coll.find({}, {b: 1, c: 1, _id: 0}).hint({a: 1, b: -1, c: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"compound.1.4 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -57,7 +57,7 @@ assert.eq(0,
var plan = coll.find({a: {$gt: 25, $lt: 43}}, {b: 1, c: 1, _id: 0})
.hint({a: 1, b: -1, c: 1})
.explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"compound.1.5 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -67,7 +67,7 @@ assert.eq(0,
var plan = coll.find({a: 38, b: "strvar_12", c: {$in: [5, 8]}}, {b: 1, c: 1, _id: 0})
.hint({a: 1, b: -1, c: 1})
.explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"compound.1.6 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -77,7 +77,7 @@ assert.eq(0,
var plan = coll.find({a: 38, b: "strvar_12", c: 55}, {a: 1, b: 1, c: 1, _id: 0})
.hint({a: 1, b: -1, c: 1})
.explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"compound.1.7 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
diff --git a/jstests/core/covered_index_negative_1.js b/jstests/core/covered_index_negative_1.js
index 37a9b4dc3bb..2c684e0e7bb 100644
--- a/jstests/core/covered_index_negative_1.js
+++ b/jstests/core/covered_index_negative_1.js
@@ -20,7 +20,7 @@ coll.ensureIndex({f: "hashed"});
// Test no projection
var plan =
coll.find({a: 10, b: "strvar_10", c: 0}).hint({a: 1, b: -1, c: 1}).explain("executionStats");
-assert(!isIndexOnly(plan.queryPlanner.winningPlan),
+assert(!isIndexOnly(db, plan.queryPlanner.winningPlan),
"negative.1.1 - indexOnly should be false on a non covered query");
assert.neq(0,
plan.executionStats.totalDocsExamined,
@@ -30,7 +30,7 @@ assert.neq(0,
var plan = coll.find({a: 10, b: "strvar_10", c: 0}, {a: 1, b: 1, c: 1})
.hint({a: 1, b: -1, c: 1})
.explain("executionStats");
-assert(!isIndexOnly(plan.queryPlanner.winningPlan),
+assert(!isIndexOnly(db, plan.queryPlanner.winningPlan),
"negative.1.2 - indexOnly should be false on a non covered query");
assert.neq(0,
plan.executionStats.totalDocsExamined,
@@ -38,7 +38,7 @@ assert.neq(0,
// Test projection of non-indexed field
var plan = coll.find({d: 100}, {d: 1, c: 1, _id: 0}).hint({d: 1}).explain("executionStats");
-assert(!isIndexOnly(plan.queryPlanner.winningPlan),
+assert(!isIndexOnly(db, plan.queryPlanner.winningPlan),
"negative.1.3 - indexOnly should be false on a non covered query");
assert.neq(0,
plan.executionStats.totalDocsExamined,
@@ -46,7 +46,7 @@ assert.neq(0,
// Test query and projection on a multi-key index
var plan = coll.find({e: 99}, {e: 1, _id: 0}).hint({e: 1}).explain("executionStats");
-assert(!isIndexOnly(plan.queryPlanner.winningPlan),
+assert(!isIndexOnly(db, plan.queryPlanner.winningPlan),
"negative.1.4 - indexOnly should be false on a non covered query");
assert.neq(0,
plan.executionStats.totalDocsExamined,
@@ -74,7 +74,7 @@ assert.neq(0,
var plan = coll.find({d: {$lt: 1000}}, {a: 1, b: 1, c: 1, _id: 0})
.hint({a: 1, b: -1, c: 1})
.explain("executionStats");
-assert(!isIndexOnly(plan.queryPlanner.winningPlan),
+assert(!isIndexOnly(db, plan.queryPlanner.winningPlan),
"negative.1.7 - indexOnly should be false on a non covered query");
assert.neq(0,
plan.executionStats.totalDocsExamined,
@@ -82,7 +82,7 @@ assert.neq(0,
// Test query on hashed indexed field
var plan = coll.find({f: 10}, {f: 1, _id: 0}).hint({f: "hashed"}).explain("executionStats");
-assert(!isIndexOnly(plan.queryPlanner.winningPlan),
+assert(!isIndexOnly(db, plan.queryPlanner.winningPlan),
"negative.1.8 - indexOnly should be false on a non covered query");
assert.neq(0,
plan.executionStats.totalDocsExamined,
diff --git a/jstests/core/covered_index_simple_1.js b/jstests/core/covered_index_simple_1.js
index b9e33f650dd..8e9bc782e1e 100644
--- a/jstests/core/covered_index_simple_1.js
+++ b/jstests/core/covered_index_simple_1.js
@@ -26,7 +26,7 @@ coll.ensureIndex({foo: 1});
// Test equality with int value
var plan = coll.find({foo: 1}, {foo: 1, _id: 0}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.1.1 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -34,7 +34,7 @@ assert.eq(0,
// Test equality with string value
var plan = coll.find({foo: "string"}, {foo: 1, _id: 0}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.1.2 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -42,7 +42,7 @@ assert.eq(0,
// Test equality with doc value
var plan = coll.find({foo: {bar: 1}}, {foo: 1, _id: 0}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.1.3 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -50,7 +50,7 @@ assert.eq(0,
// Test no query
var plan = coll.find({}, {foo: 1, _id: 0}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.1.4 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -59,7 +59,7 @@ assert.eq(0,
// Test range query
var plan =
coll.find({foo: {$gt: 2, $lt: 6}}, {foo: 1, _id: 0}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.1.5 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -68,7 +68,7 @@ assert.eq(0,
// Test in query
var plan =
coll.find({foo: {$in: [5, 8]}}, {foo: 1, _id: 0}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.1.6 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -76,7 +76,7 @@ assert.eq(0,
// Test no return
var plan = coll.find({foo: "2"}, {foo: 1, _id: 0}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.1.7 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
diff --git a/jstests/core/covered_index_simple_2.js b/jstests/core/covered_index_simple_2.js
index 0974ee0eb50..71da45922db 100644
--- a/jstests/core/covered_index_simple_2.js
+++ b/jstests/core/covered_index_simple_2.js
@@ -20,7 +20,7 @@ coll.ensureIndex({foo: 1}, {unique: true});
// Test equality with int value
var plan = coll.find({foo: 1}, {foo: 1, _id: 0}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.2.1 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -28,7 +28,7 @@ assert.eq(0,
// Test equality with string value
var plan = coll.find({foo: "string"}, {foo: 1, _id: 0}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.2.2 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -36,7 +36,7 @@ assert.eq(0,
// Test equality with int value on a dotted field
var plan = coll.find({foo: {bar: 1}}, {foo: 1, _id: 0}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.2.3 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -44,7 +44,7 @@ assert.eq(0,
// Test no query
var plan = coll.find({}, {foo: 1, _id: 0}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.2.4 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -53,7 +53,7 @@ assert.eq(0,
// Test range query
var plan =
coll.find({foo: {$gt: 2, $lt: 6}}, {foo: 1, _id: 0}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.2.5 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -62,7 +62,7 @@ assert.eq(0,
// Test in query
var plan =
coll.find({foo: {$in: [5, 8]}}, {foo: 1, _id: 0}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.2.6 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
diff --git a/jstests/core/covered_index_simple_3.js b/jstests/core/covered_index_simple_3.js
index 7d021a17ca8..b53ce20d85f 100644
--- a/jstests/core/covered_index_simple_3.js
+++ b/jstests/core/covered_index_simple_3.js
@@ -23,7 +23,7 @@ coll.ensureIndex({foo: 1}, {sparse: true, unique: true});
// Test equality with int value
var plan = coll.find({foo: 1}, {foo: 1, _id: 0}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.3.1 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -31,7 +31,7 @@ assert.eq(0,
// Test equality with string value
var plan = coll.find({foo: "string"}, {foo: 1, _id: 0}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.3.2 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -39,7 +39,7 @@ assert.eq(0,
// Test equality with int value on a dotted field
var plan = coll.find({foo: {bar: 1}}, {foo: 1, _id: 0}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.3.3 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -47,7 +47,7 @@ assert.eq(0,
// Test no query
var plan = coll.find({}, {foo: 1, _id: 0}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.3.4 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -56,7 +56,7 @@ assert.eq(0,
// Test range query
var plan =
coll.find({foo: {$gt: 2, $lt: 6}}, {foo: 1, _id: 0}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.3.5 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -65,7 +65,7 @@ assert.eq(0,
// Test in query
var plan =
coll.find({foo: {$in: [5, 8]}}, {foo: 1, _id: 0}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.3.6 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -74,7 +74,7 @@ assert.eq(0,
// Test $exists true
var plan =
coll.find({foo: {$exists: true}}, {foo: 1, _id: 0}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.3.7 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -85,7 +85,7 @@ coll.dropIndexes();
coll.ensureIndex({bar: 1});
var plan =
coll.find({bar: {$nin: [5, 8]}}, {bar: 1, _id: 0}).hint({bar: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.3.8 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
diff --git a/jstests/core/covered_index_simple_id.js b/jstests/core/covered_index_simple_id.js
index c2550544abd..e7c25cc687a 100644
--- a/jstests/core/covered_index_simple_id.js
+++ b/jstests/core/covered_index_simple_id.js
@@ -14,7 +14,7 @@ coll.insert({_id: null});
// Test equality with int value
var plan = coll.find({_id: 1}, {_id: 1}).hint({_id: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.id.1 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -22,7 +22,7 @@ assert.eq(0,
// Test equality with string value
var plan = coll.find({_id: "string"}, {_id: 1}).hint({_id: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.id.2 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -30,7 +30,7 @@ assert.eq(0,
// Test equality with int value on a dotted field
var plan = coll.find({_id: {bar: 1}}, {_id: 1}).hint({_id: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.id.3 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -38,7 +38,7 @@ assert.eq(0,
// Test no query
var plan = coll.find({}, {_id: 1}).hint({_id: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.id.4 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -46,7 +46,7 @@ assert.eq(0,
// Test range query
var plan = coll.find({_id: {$gt: 2, $lt: 6}}, {_id: 1}).hint({_id: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.id.5 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -54,7 +54,7 @@ assert.eq(0,
// Test in query
var plan = coll.find({_id: {$in: [5, 8]}}, {_id: 1}).hint({_id: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"simple.id.6 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
diff --git a/jstests/core/covered_index_sort_1.js b/jstests/core/covered_index_sort_1.js
index a65cc415ea4..1a7ac940efa 100644
--- a/jstests/core/covered_index_sort_1.js
+++ b/jstests/core/covered_index_sort_1.js
@@ -26,7 +26,7 @@ coll.ensureIndex({foo: 1});
// Test no query and sort ascending
var plan = coll.find({}, {foo: 1, _id: 0}).sort({foo: 1}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"sort.1.1 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -34,7 +34,7 @@ assert.eq(0,
// Test no query and sort descending
var plan = coll.find({}, {foo: 1, _id: 0}).sort({foo: -1}).hint({foo: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"sort.1.2 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
@@ -45,7 +45,7 @@ var plan = coll.find({foo: {$gt: 2}}, {foo: 1, _id: 0})
.sort({foo: -1})
.hint({foo: 1})
.explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"sort.1.3 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
diff --git a/jstests/core/covered_index_sort_2.js b/jstests/core/covered_index_sort_2.js
index 5ed3dc869c9..7f22b9c2867 100644
--- a/jstests/core/covered_index_sort_2.js
+++ b/jstests/core/covered_index_sort_2.js
@@ -14,7 +14,7 @@ coll.insert({_id: null});
// Test no query
var plan = coll.find({}, {_id: 1}).sort({_id: -1}).hint({_id: 1}).explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"sort.2.1 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
diff --git a/jstests/core/covered_index_sort_3.js b/jstests/core/covered_index_sort_3.js
index aeeb6f70773..6a62bafacd2 100644
--- a/jstests/core/covered_index_sort_3.js
+++ b/jstests/core/covered_index_sort_3.js
@@ -21,7 +21,7 @@ var plan = coll.find({}, {b: 1, c: 1, _id: 0})
.sort({a: 1, b: -1, c: 1})
.hint({a: 1, b: -1, c: 1})
.explain("executionStats");
-assert(isIndexOnly(plan.queryPlanner.winningPlan),
+assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"sort.3.1 - indexOnly should be true on covered query");
assert.eq(0,
plan.executionStats.totalDocsExamined,
diff --git a/jstests/core/covered_multikey.js b/jstests/core/covered_multikey.js
index db1aaf9c525..9607b48841d 100644
--- a/jstests/core/covered_multikey.js
+++ b/jstests/core/covered_multikey.js
@@ -25,11 +25,11 @@
assert.eq(1, coll.find({a: 1, b: 2}, {_id: 0, a: 1}).itcount());
assert.eq({a: 1}, coll.findOne({a: 1, b: 2}, {_id: 0, a: 1}));
let explainRes = coll.explain("queryPlanner").find({a: 1, b: 2}, {_id: 0, a: 1}).finish();
- assert(isIxscan(explainRes.queryPlanner.winningPlan));
+ assert(isIxscan(db, explainRes.queryPlanner.winningPlan));
if (isMMAPv1) {
- assert(planHasStage(explainRes.queryPlanner.winningPlan, "FETCH"));
+ assert(planHasStage(db, explainRes.queryPlanner.winningPlan, "FETCH"));
} else {
- assert(!planHasStage(explainRes.queryPlanner.winningPlan, "FETCH"));
+ assert(!planHasStage(db, explainRes.queryPlanner.winningPlan, "FETCH"));
}
coll.drop();
@@ -46,9 +46,9 @@
.sort({c: -1, d: -1})
.finish();
if (isMMAPv1) {
- assert(planHasStage(explainRes.queryPlanner.winningPlan, "FETCH"));
+ assert(planHasStage(db, explainRes.queryPlanner.winningPlan, "FETCH"));
} else {
- assert(!planHasStage(explainRes.queryPlanner.winningPlan, "FETCH"));
+ assert(!planHasStage(db, explainRes.queryPlanner.winningPlan, "FETCH"));
}
// Verify that a query cannot be covered over a path which is multikey due to an empty array.
@@ -57,8 +57,8 @@
assert.commandWorked(coll.createIndex({a: 1}));
assert.eq({a: []}, coll.findOne({a: []}, {_id: 0, a: 1}));
explainRes = coll.explain("queryPlanner").find({a: []}, {_id: 0, a: 1}).finish();
- assert(planHasStage(explainRes.queryPlanner.winningPlan, "IXSCAN"));
- assert(planHasStage(explainRes.queryPlanner.winningPlan, "FETCH"));
+ assert(planHasStage(db, explainRes.queryPlanner.winningPlan, "IXSCAN"));
+ assert(planHasStage(db, explainRes.queryPlanner.winningPlan, "FETCH"));
let ixscanStage = getPlanStage(explainRes.queryPlanner.winningPlan, "IXSCAN");
assert.eq(true, ixscanStage.isMultiKey);
@@ -69,8 +69,8 @@
assert.commandWorked(coll.createIndex({a: 1}));
assert.eq({a: [2]}, coll.findOne({a: 2}, {_id: 0, a: 1}));
explainRes = coll.explain("queryPlanner").find({a: 2}, {_id: 0, a: 1}).finish();
- assert(planHasStage(explainRes.queryPlanner.winningPlan, "IXSCAN"));
- assert(planHasStage(explainRes.queryPlanner.winningPlan, "FETCH"));
+ assert(planHasStage(db, explainRes.queryPlanner.winningPlan, "IXSCAN"));
+ assert(planHasStage(db, explainRes.queryPlanner.winningPlan, "FETCH"));
ixscanStage = getPlanStage(explainRes.queryPlanner.winningPlan, "IXSCAN");
assert.eq(true, ixscanStage.isMultiKey);
@@ -82,8 +82,8 @@
assert.writeOK(coll.update({}, {$set: {a: [2]}}));
assert.eq({a: [2]}, coll.findOne({a: 2}, {_id: 0, a: 1}));
explainRes = coll.explain("queryPlanner").find({a: 2}, {_id: 0, a: 1}).finish();
- assert(planHasStage(explainRes.queryPlanner.winningPlan, "IXSCAN"));
- assert(planHasStage(explainRes.queryPlanner.winningPlan, "FETCH"));
+ assert(planHasStage(db, explainRes.queryPlanner.winningPlan, "IXSCAN"));
+ assert(planHasStage(db, explainRes.queryPlanner.winningPlan, "FETCH"));
ixscanStage = getPlanStage(explainRes.queryPlanner.winningPlan, "IXSCAN");
assert.eq(true, ixscanStage.isMultiKey);
diff --git a/jstests/core/distinct_array1.js b/jstests/core/distinct_array1.js
index 679395a064b..0ce6cf100f6 100644
--- a/jstests/core/distinct_array1.js
+++ b/jstests/core/distinct_array1.js
@@ -8,30 +8,28 @@ t.save({a: 9});
// Without index.
res = t.distinct("a").sort();
-assert.eq("1,2,3,4,5,9", res.toString(), "A1");
+assert.eq("1,2,3,4,5,9", res.toString());
// Array element 0 without index.
res = t.distinct("a.0").sort();
-assert.eq("1,2,3", res.toString(), "A2");
+assert.eq("1,2,3", res.toString());
// Array element 1 without index.
res = t.distinct("a.1").sort();
-assert.eq("2,3,4", res.toString(), "A3");
+assert.eq("2,3,4", res.toString());
// With index.
t.ensureIndex({a: 1});
res = t.distinct("a").sort();
-assert.eq("1,2,3,4,5,9", res.toString(), "A4");
+assert.eq("1,2,3,4,5,9", res.toString());
// Array element 0 with index.
res = t.distinct("a.0").sort();
-assert.eq("1,2,3", res.toString(), "A5");
+assert.eq("1,2,3", res.toString());
// Array element 1 with index.
res = t.distinct("a.1").sort();
-assert.eq("2,3,4", res.toString(), "A6");
-
-// t.drop();
+assert.eq("2,3,4", res.toString());
t.save({a: [{b: "a"}, {b: "d"}], c: 12});
t.save({a: [{b: "b"}, {b: "d"}], c: 12});
@@ -42,21 +40,31 @@ t.save({a: {b: "z"}, c: 12});
// Without index.
res = t.distinct("a.b").sort();
-assert.eq("a,b,c,d,e,f,z", res.toString(), "B1");
+assert.eq("a,b,c,d,e,f,z", res.toString());
// Array element 0 without index
res = t.distinct("a.0.b").sort();
-assert.eq("a,b,c", res.toString(), "B2");
+assert.eq("a,b,c", res.toString());
// Array element 1 without index
res = t.distinct("a.1.b").sort();
-assert.eq("d,e,f", res.toString(), "B3");
+assert.eq("d,e,f", res.toString());
// With index.
t.ensureIndex({"a.b": 1});
res = t.distinct("a.b");
res.sort();
-assert.eq("a,b,c,d,e,f,z", res.toString(), "B4");
+// TODO SERVER-14832 The presence of an index may change results, but only if the index is not
+// multikey.
+// In a sharded scenario, an unlucky distribution of data will cause all the arrays to go to one
+// shard, and one shard be left with only non-multikey documents, including one with {a: 9}, which
+// will generate a null result.
+if (res.includes(null)) {
+ // The default sorting of an array is by string, so null will appear in an odd position.
+ assert.eq(res, ["a", "b", "c", "d", "e", "f", null, "z"]);
+} else {
+ assert.eq("a,b,c,d,e,f,z", res.toString());
+}
// _id as an document containing an array
t.save({_id: {a: [1, 2, 3]}});
@@ -66,25 +74,25 @@ t.save({_id: {a: 9}});
// Without index.
res = t.distinct("_id.a").sort();
-assert.eq("1,2,3,4,5,9", res.toString(), "C1");
+assert.eq("1,2,3,4,5,9", res.toString());
// Array element 0 without index.
res = t.distinct("_id.a.0").sort();
-assert.eq("1,2,3", res.toString(), "C2");
+assert.eq("1,2,3", res.toString());
// Array element 1 without index.
res = t.distinct("_id.a.1").sort();
-assert.eq("2,3,4", res.toString(), "C3");
+assert.eq("2,3,4", res.toString());
// With index.
t.ensureIndex({"_id.a": 1});
res = t.distinct("_id.a").sort();
-assert.eq("1,2,3,4,5,9", res.toString(), "C4");
+assert.eq("1,2,3,4,5,9", res.toString());
// Array element 0 with index.
res = t.distinct("_id.a.0").sort();
-assert.eq("1,2,3", res.toString(), "C5");
+assert.eq("1,2,3", res.toString());
// Array element 1 with index.
res = t.distinct("_id.a.1").sort();
-assert.eq("2,3,4", res.toString(), "C6");
+assert.eq("2,3,4", res.toString());
diff --git a/jstests/core/distinct_compound_index.js b/jstests/core/distinct_compound_index.js
index 9b7c0226265..12dffab8bde 100644
--- a/jstests/core/distinct_compound_index.js
+++ b/jstests/core/distinct_compound_index.js
@@ -1,7 +1,8 @@
(function() {
"use strict";
- load("jstests/libs/analyze_plan.js");
+ load("jstests/libs/fixture_helpers.js"); // For FixtureHelpers.
+ load("jstests/libs/analyze_plan.js"); // For planHasStage.
var coll = db.distinct_multikey_index;
@@ -16,13 +17,17 @@
var explain_distinct_with_query = coll.explain("executionStats").distinct('b', {a: 1});
assert.commandWorked(explain_distinct_with_query);
- assert(planHasStage(explain_distinct_with_query.queryPlanner.winningPlan, "DISTINCT_SCAN"));
- assert(planHasStage(explain_distinct_with_query.queryPlanner.winningPlan, "PROJECTION"));
- assert.eq(2, explain_distinct_with_query.executionStats.nReturned);
+ assert(planHasStage(db, explain_distinct_with_query.queryPlanner.winningPlan, "DISTINCT_SCAN"));
+ assert(planHasStage(db, explain_distinct_with_query.queryPlanner.winningPlan, "PROJECTION"));
+ // If the collection is sharded, we expect at most 2 distinct values per shard. If the
+ // collection is not sharded, we expect 2 returned.
+ assert.lte(2 * FixtureHelpers.numberOfShardsForCollection(coll),
+ explain_distinct_with_query.executionStats.nReturned);
var explain_distinct_without_query = coll.explain("executionStats").distinct('b');
assert.commandWorked(explain_distinct_without_query);
- assert(planHasStage(explain_distinct_without_query.queryPlanner.winningPlan, "COLLSCAN"));
- assert(!planHasStage(explain_distinct_without_query.queryPlanner.winningPlan, "DISTINCT_SCAN"));
+ assert(planHasStage(db, explain_distinct_without_query.queryPlanner.winningPlan, "COLLSCAN"));
+ assert(!planHasStage(
+ db, explain_distinct_without_query.queryPlanner.winningPlan, "DISTINCT_SCAN"));
assert.eq(40, explain_distinct_without_query.executionStats.nReturned);
})();
diff --git a/jstests/core/distinct_index1.js b/jstests/core/distinct_index1.js
index 63f61b8292c..34da35a2b60 100644
--- a/jstests/core/distinct_index1.js
+++ b/jstests/core/distinct_index1.js
@@ -20,42 +20,42 @@ for (i = 0; i < 1000; i++) {
x = d("a");
// Collection scan looks at all 1000 documents and gets 1000
// distinct values. Looks at 0 index keys.
-assert.eq(1000, x.executionStats.nReturned, "AA1");
-assert.eq(0, x.executionStats.totalKeysExamined, "AA2");
-assert.eq(1000, x.executionStats.totalDocsExamined, "AA3");
+assert.eq(1000, x.executionStats.nReturned);
+assert.eq(0, x.executionStats.totalKeysExamined);
+assert.eq(1000, x.executionStats.totalDocsExamined);
x = d("a", {a: {$gt: 5}});
// Collection scan looks at all 1000 documents and gets 398
// distinct values which match the query. Looks at 0 index keys.
-assert.eq(398, x.executionStats.nReturned, "AB1");
-assert.eq(0, x.executionStats.totalKeysExamined, "AB2");
-assert.eq(1000, x.executionStats.totalDocsExamined, "AB3");
+assert.eq(398, x.executionStats.nReturned);
+assert.eq(0, x.executionStats.totalKeysExamined);
+assert.eq(1000, x.executionStats.totalDocsExamined);
x = d("b", {a: {$gt: 5}});
// Collection scan looks at all 1000 documents and gets 398
// distinct values which match the query. Looks at 0 index keys.
-assert.eq(398, x.executionStats.nReturned, "AC1");
-assert.eq(0, x.executionStats.totalKeysExamined, "AC2");
-assert.eq(1000, x.executionStats.totalDocsExamined, "AC3");
+assert.eq(398, x.executionStats.nReturned);
+assert.eq(0, x.executionStats.totalKeysExamined);
+assert.eq(1000, x.executionStats.totalDocsExamined);
t.ensureIndex({a: 1});
x = d("a");
// There are only 10 values. We use the fast distinct hack and only examine each value once.
-assert.eq(10, x.executionStats.nReturned, "BA1");
-assert.eq(10, x.executionStats.totalKeysExamined, "BA2");
+assert.eq(10, x.executionStats.nReturned);
+assert.lte(10, x.executionStats.totalKeysExamined);
x = d("a", {a: {$gt: 5}});
// Only 4 values of a are >= 5 and we use the fast distinct hack.
-assert.eq(4, x.executionStats.nReturned, "BB1");
-assert.eq(4, x.executionStats.totalKeysExamined, "BB2");
-assert.eq(0, x.executionStats.totalDocsExamined, "BB3");
+assert.eq(4, x.executionStats.nReturned);
+assert.eq(4, x.executionStats.totalKeysExamined);
+assert.eq(0, x.executionStats.totalDocsExamined);
x = d("b", {a: {$gt: 5}});
// We can't use the fast distinct hack here because we're distinct-ing over 'b'.
-assert.eq(398, x.executionStats.nReturned, "BC1");
-assert.eq(398, x.executionStats.totalKeysExamined, "BC2");
-assert.eq(398, x.executionStats.totalDocsExamined, "BC3");
+assert.eq(398, x.executionStats.nReturned);
+assert.eq(398, x.executionStats.totalKeysExamined);
+assert.eq(398, x.executionStats.totalDocsExamined);
// Test that a distinct over a trailing field of the index can be covered.
t.dropIndexes();
@@ -63,12 +63,12 @@ t.ensureIndex({a: 1, b: 1});
x = d("b", {a: {$gt: 5}, b: {$gt: 5}});
printjson(x);
assert.lte(x.executionStats.nReturned, 171);
-assert.eq(0, x.executionStats.totalDocsExamined, "BD3");
+assert.eq(0, x.executionStats.totalDocsExamined);
// Should use an index scan over the hashed index.
t.dropIndexes();
t.ensureIndex({a: "hashed"});
x = d("a", {$or: [{a: 3}, {a: 5}]});
-assert.eq(188, x.executionStats.nReturned, "DA1");
+assert.eq(188, x.executionStats.nReturned);
var indexScanStage = getPlanStage(x.executionStats.executionStages, "IXSCAN");
assert.eq("hashed", indexScanStage.keyPattern.a);
diff --git a/jstests/core/distinct_multikey.js b/jstests/core/distinct_multikey.js
index ac9e69ff00f..e2250fbbe93 100644
--- a/jstests/core/distinct_multikey.js
+++ b/jstests/core/distinct_multikey.js
@@ -19,16 +19,16 @@
let result = coll.distinct("a");
assert.eq([1, 2, 3, 4, 5, 6, 7], result.sort());
let explain = coll.explain("queryPlanner").distinct("a");
- assert(planHasStage(explain.queryPlanner.winningPlan, "PROJECTION"));
- assert(planHasStage(explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "PROJECTION"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
// Test that distinct can correctly use a multikey index when there is a predicate. This query
// should not be eligible for the distinct scan and cannot be covered.
result = coll.distinct("a", {a: 3});
assert.eq([1, 2, 3, 4], result.sort());
explain = coll.explain("queryPlanner").distinct("a", {a: 3});
- assert(planHasStage(explain.queryPlanner.winningPlan, "FETCH"));
- assert(planHasStage(explain.queryPlanner.winningPlan, "IXSCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "FETCH"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "IXSCAN"));
// Test distinct over a dotted multikey field, with a predicate.
coll.drop();
@@ -39,8 +39,8 @@
result = coll.distinct("a.b", {"a.b": 3});
assert.eq([1, 2, 3, 4], result.sort());
explain = coll.explain("queryPlanner").distinct("a.b", {"a.b": 3});
- assert(planHasStage(explain.queryPlanner.winningPlan, "FETCH"));
- assert(planHasStage(explain.queryPlanner.winningPlan, "IXSCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "FETCH"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "IXSCAN"));
// Test that the distinct scan can be used when there is a predicate and the index is not
// multikey.
@@ -53,8 +53,8 @@
result = coll.distinct("a", {a: {$gte: 2}});
assert.eq([2, 3], result.sort());
explain = coll.explain("queryPlanner").distinct("a", {a: {$gte: 2}});
- assert(planHasStage(explain.queryPlanner.winningPlan, "PROJECTION"));
- assert(planHasStage(explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "PROJECTION"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
// Test a distinct which can use a multikey index, where the field being distinct'ed is not
// multikey.
@@ -70,19 +70,19 @@
if (isMMAPv1) {
// MMAPv1 does not support path-level multikey metadata tracking. It cannot use a distinct
// scan since it does not know that the "a" field is not multikey.
- assert(planHasStage(explain.queryPlanner.winningPlan, "FETCH"));
- assert(planHasStage(explain.queryPlanner.winningPlan, "IXSCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "FETCH"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "IXSCAN"));
} else {
- assert(planHasStage(explain.queryPlanner.winningPlan, "PROJECTION"));
- assert(planHasStage(explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "PROJECTION"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
}
// Test distinct over a trailing multikey field.
result = coll.distinct("b", {a: {$gte: 2}});
assert.eq([3, 4, 5], result.sort());
explain = coll.explain("queryPlanner").distinct("b", {a: {$gte: 2}});
- assert(planHasStage(explain.queryPlanner.winningPlan, "FETCH"));
- assert(planHasStage(explain.queryPlanner.winningPlan, "IXSCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "FETCH"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "IXSCAN"));
// Test distinct over a trailing non-multikey field, where the leading field is multikey.
coll.drop();
@@ -97,11 +97,11 @@
if (isMMAPv1) {
// MMAPv1 does not support path-level multikey metadata tracking. It cannot use a distinct
// scan since it does not know that the "a" field is not multikey.
- assert(planHasStage(explain.queryPlanner.winningPlan, "FETCH"));
- assert(planHasStage(explain.queryPlanner.winningPlan, "IXSCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "FETCH"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "IXSCAN"));
} else {
- assert(planHasStage(explain.queryPlanner.winningPlan, "PROJECTION"));
- assert(planHasStage(explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "PROJECTION"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
}
// Test distinct over a trailing non-multikey dotted path where the leading field is multikey.
@@ -117,10 +117,10 @@
if (isMMAPv1) {
// MMAPv1 does not support path-level multikey metadata tracking. It cannot use a distinct
// scan since it does not know that the "a" field is not multikey.
- assert(planHasStage(explain.queryPlanner.winningPlan, "FETCH"));
- assert(planHasStage(explain.queryPlanner.winningPlan, "IXSCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "FETCH"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "IXSCAN"));
} else {
- assert(planHasStage(explain.queryPlanner.winningPlan, "PROJECTION"));
- assert(planHasStage(explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "PROJECTION"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
}
}());
diff --git a/jstests/core/explain2.js b/jstests/core/explain2.js
index a0a65de4fe9..ec9a79b16c8 100644
--- a/jstests/core/explain2.js
+++ b/jstests/core/explain2.js
@@ -1,4 +1,7 @@
// Test calculation of the 'millis' field in explain output.
+// This test makes assertions on how long a particular query will sleep. When the collection is
+// sharded each shard may sleep for less time than is expected.
+// @tags: [assumes_unsharded_collection]
t = db.jstests_explain2;
t.drop();
diff --git a/jstests/core/explain_count.js b/jstests/core/explain_count.js
index 0351db29f9c..ee7cb31de94 100644
--- a/jstests/core/explain_count.js
+++ b/jstests/core/explain_count.js
@@ -15,13 +15,17 @@ function checkCountExplain(explain, nCounted) {
printjson(explain);
var execStages = explain.executionStats.executionStages;
- // If passed through mongos, then the root stage should be the mongos SINGLE_SHARD stage,
- // with COUNT as its child. If explaining directly on the shard, then COUNT is the root
- // stage.
- if ("SINGLE_SHARD" == execStages.stage) {
- var countStage = execStages.shards[0].executionStages;
- assert.eq(countStage.stage, "COUNT", "root stage on shard is not COUNT");
- assert.eq(countStage.nCounted, nCounted, "wrong count result");
+ // If passed through mongos, then the root stage should be the mongos SINGLE_SHARD stage or
+ // SHARD_MERGE stages, with COUNT as the root stage on each shard. If explaining directly on the
+ // shard, then COUNT is the root stage.
+ if ("SINGLE_SHARD" == execStages.stage || "SHARD_MERGE" == execStages.stage) {
+ let totalCounted = 0;
+ for (let shardExplain of execStages.shards) {
+ const countStage = shardExplain.executionStages;
+ assert.eq(countStage.stage, "COUNT", "root stage on shard is not COUNT");
+ totalCounted += countStage.nCounted;
+ }
+ assert.eq(totalCounted, nCounted, "wrong count result");
} else {
assert.eq(execStages.stage, "COUNT", "root stage is not COUNT");
assert.eq(execStages.nCounted, nCounted, "wrong count result");
diff --git a/jstests/core/explain_delete.js b/jstests/core/explain_delete.js
index ce8fd59363b..d65a4b1f748 100644
--- a/jstests/core/explain_delete.js
+++ b/jstests/core/explain_delete.js
@@ -19,13 +19,17 @@ function checkNWouldDelete(explain, nWouldDelete) {
var executionStats = explain.executionStats;
assert("executionStages" in executionStats);
- // If passed through mongos, then DELETE should be below the SINGLE_SHARD mongos stage.
- // Otherwise it is the root stage.
+ // If passed through mongos, then DELETE stage(s) should be below the SHARD_WRITE mongos stage.
+ // Otherwise the DELETE stage is the root stage.
var execStages = executionStats.executionStages;
if ("SHARD_WRITE" === execStages.stage) {
- var deleteStage = execStages.shards[0].executionStages;
- assert.eq(deleteStage.stage, "DELETE");
- assert.eq(deleteStage.nWouldDelete, nWouldDelete);
+ let totalToBeDeletedAcrossAllShards = 0;
+ execStages.shards.forEach(function(shardExplain) {
+ const rootStageName = shardExplain.executionStages.stage;
+ assert.eq(rootStageName, "DELETE", tojson(execStages));
+ totalToBeDeletedAcrossAllShards += shardExplain.executionStages.nWouldDelete;
+ });
+ assert.eq(totalToBeDeletedAcrossAllShards, nWouldDelete);
} else {
assert.eq(execStages.stage, "DELETE");
assert.eq(execStages.nWouldDelete, nWouldDelete);
diff --git a/jstests/core/explain_distinct.js b/jstests/core/explain_distinct.js
index 4cc9eab4eab..5f9fda44d18 100644
--- a/jstests/core/explain_distinct.js
+++ b/jstests/core/explain_distinct.js
@@ -28,7 +28,7 @@
// Collection doesn't exist.
var explain = runDistinctExplain(coll, 'a', {});
assert.commandWorked(explain);
- assert(planHasStage(explain.queryPlanner.winningPlan, "EOF"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "EOF"));
// Insert the data to perform distinct() on.
for (var i = 0; i < 10; i++) {
@@ -50,7 +50,7 @@
var explain = runDistinctExplain(coll, 'b', {});
assert.commandWorked(explain);
assert.eq(20, explain.executionStats.nReturned);
- assert(isCollscan(explain.queryPlanner.winningPlan));
+ assert(isCollscan(db, explain.queryPlanner.winningPlan));
assert.commandWorked(coll.createIndex({a: 1}));
@@ -58,8 +58,8 @@
var explain = runDistinctExplain(coll, 'a', {});
assert.commandWorked(explain);
assert.eq(2, explain.executionStats.nReturned);
- assert(planHasStage(explain.queryPlanner.winningPlan, "PROJECTION"));
- assert(planHasStage(explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "PROJECTION"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
// Check that the DISTINCT_SCAN stage has the correct stats.
var stage = getPlanStage(explain.queryPlanner.winningPlan, "DISTINCT_SCAN");
@@ -78,14 +78,14 @@
var explain = runDistinctExplain(coll, 'a', {a: 1});
assert.commandWorked(explain);
assert.eq(1, explain.executionStats.nReturned);
- assert(planHasStage(explain.queryPlanner.winningPlan, "PROJECTION"));
- assert(planHasStage(explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "PROJECTION"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
assert.eq([1], coll.distinct('b', {a: 1}));
var explain = runDistinctExplain(coll, 'b', {a: 1});
assert.commandWorked(explain);
assert.eq(1, explain.executionStats.nReturned);
- assert(!planHasStage(explain.queryPlanner.winningPlan, "FETCH"));
- assert(planHasStage(explain.queryPlanner.winningPlan, "PROJECTION"));
- assert(planHasStage(explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
+ assert(!planHasStage(db, explain.queryPlanner.winningPlan, "FETCH"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "PROJECTION"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
})();
diff --git a/jstests/core/explain_execution_error.js b/jstests/core/explain_execution_error.js
index 98de41289df..ff999f48bb9 100644
--- a/jstests/core/explain_execution_error.js
+++ b/jstests/core/explain_execution_error.js
@@ -3,6 +3,8 @@
// Test that even when the execution of a query fails, explain reports query
// planner information.
+load("jstests/libs/fixture_helpers.js"); // For FixtureHelpers.
+
var t = db.explain_execution_error;
t.drop();
@@ -12,36 +14,53 @@ var result;
* Asserts that explain reports an error in its execution stats section.
*/
function assertExecError(explain) {
- var errorObj;
-
- var execStats = explain.executionStats;
- if (execStats.executionStages.stage == "SINGLE_SHARD") {
- errorObj = execStats.executionStages.shards[0];
+ // Gather the exec stats from all shards.
+ let allExecStats = [];
+ let topLevelExecStats = explain.executionStats;
+ if (topLevelExecStats.executionStages.stage == "SINGLE_SHARD" ||
+ topLevelExecStats.executionStages.stage == "SHARD_MERGE_SORT") {
+ allExecStats = topLevelExecStats.executionStages.shards;
} else {
- errorObj = execStats;
+ allExecStats.push(topLevelExecStats);
}
- assert.eq(false, errorObj.executionSuccess);
- assert("errorMessage" in errorObj);
- assert("errorCode" in errorObj);
+ // In a sharded environment, we only know that at least one of the shards will fail, we can't
+ // expect all of them to fail, since there may be different amounts of data on each shard.
+ let haveSeenExecutionFailure = false;
+ for (let execStats of allExecStats) {
+ if (!execStats.executionSuccess) {
+ haveSeenExecutionFailure = true;
+ assert("errorMessage" in execStats,
+ `Expected "errorMessage" to be present in ${tojson(execStats)}`);
+ assert("errorCode" in execStats,
+ `Expected "errorCode" to be present in ${tojson(execStats)}`);
+ }
+ }
+ assert(haveSeenExecutionFailure,
+ `Expected at least one shard to have failed: ${tojson(explain)}`);
}
/**
* Asserts that explain reports success in its execution stats section.
*/
function assertExecSuccess(explain) {
- var errorObj;
+ let errorObjs = [];
- var execStats = explain.executionStats;
- if (execStats.executionStages.stage == "SINGLE_SHARD") {
- errorObj = execStats.executionStages.shards[0];
+ let execStats = explain.executionStats;
+ if (execStats.executionStages.stage == "SINGLE_SHARD" ||
+ execStats.executionStages.stage == "SHARD_MERGE_SORT") {
+ errorObjs = execStats.executionStages.shards;
} else {
- errorObj = execStats;
+ errorObjs.push(execStats);
}
- assert.eq(true, errorObj.executionSuccess);
- assert(!("errorMessage" in errorObj));
- assert(!("errorCode" in errorObj));
+ for (let errorObj of errorObjs) {
+ assert.eq(true, errorObj.executionSuccess);
+ assert(!("errorMessage" in errorObj),
+ `Expected "errorMessage" not to be present in ${tojson(errorObj)}`);
+ assert(!("errorCode" in errorObj),
+ `Expected "errorCode" not to be present in ${tojson(errorObj)}`);
+ }
}
// Make a string that exceeds 1 MB.
@@ -50,8 +69,9 @@ while (bigStr.length < (1024 * 1024)) {
bigStr += bigStr;
}
-// Make a collection that is about 40 MB.
-for (var i = 0; i < 40; i++) {
+// Make a collection that is about 40 MB * number of shards.
+const numShards = FixtureHelpers.numberOfShardsForCollection(t);
+for (var i = 0; i < 40 * numShards; i++) {
assert.writeOK(t.insert({a: bigStr, b: 1, c: i}));
}
diff --git a/jstests/core/explain_multikey.js b/jstests/core/explain_multikey.js
index 9c8bcaff353..963e6c7b3dc 100644
--- a/jstests/core/explain_multikey.js
+++ b/jstests/core/explain_multikey.js
@@ -1,3 +1,8 @@
+// Tests the output of the multikey information in the explain output.
+//
+// This test examines the explain output to verify that certain indexes are multi-key, which may not
+// be the case on all shards.
+// @tags: [assumes_unsharded_collection]
(function() {
"use strict";
@@ -31,7 +36,7 @@
var explain = db.runCommand({explain: testOptions.commandObj});
assert.commandWorked(explain);
- assert(planHasStage(explain.queryPlanner.winningPlan, testOptions.stage),
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, testOptions.stage),
"expected stage to be present: " + tojson(explain));
return getPlanStage(explain.queryPlanner.winningPlan, testOptions.stage);
}
diff --git a/jstests/core/explain_shell_helpers.js b/jstests/core/explain_shell_helpers.js
index 6786e33c80b..ab06b8042e0 100644
--- a/jstests/core/explain_shell_helpers.js
+++ b/jstests/core/explain_shell_helpers.js
@@ -117,40 +117,40 @@ assert.commandWorked(explain);
// .sort()
explain = t.explain().find().sort({b: -1}).finish();
assert.commandWorked(explain);
-assert(planHasStage(explain.queryPlanner.winningPlan, "SORT"));
+assert(planHasStage(db, explain.queryPlanner.winningPlan, "SORT"));
explain = t.find().sort({b: -1}).explain();
assert.commandWorked(explain);
-assert(planHasStage(explain.queryPlanner.winningPlan, "SORT"));
+assert(planHasStage(db, explain.queryPlanner.winningPlan, "SORT"));
// .hint()
explain = t.explain().find().hint({a: 1}).finish();
assert.commandWorked(explain);
-assert(isIxscan(explain.queryPlanner.winningPlan));
+assert(isIxscan(db, explain.queryPlanner.winningPlan));
explain = t.explain().find().hint("a_1").finish();
assert.commandWorked(explain);
-assert(isIxscan(explain.queryPlanner.winningPlan));
+assert(isIxscan(db, explain.queryPlanner.winningPlan));
explain = t.find().hint({a: 1}).explain();
assert.commandWorked(explain);
-assert(isIxscan(explain.queryPlanner.winningPlan));
+assert(isIxscan(db, explain.queryPlanner.winningPlan));
explain = t.find().hint("a_1").explain();
assert.commandWorked(explain);
-assert(isIxscan(explain.queryPlanner.winningPlan));
+assert(isIxscan(db, explain.queryPlanner.winningPlan));
// .min()
explain = t.explain().find().min({a: 1}).finish();
assert.commandWorked(explain);
-assert(isIxscan(explain.queryPlanner.winningPlan));
+assert(isIxscan(db, explain.queryPlanner.winningPlan));
explain = t.find().min({a: 1}).explain();
assert.commandWorked(explain);
-assert(isIxscan(explain.queryPlanner.winningPlan));
+assert(isIxscan(db, explain.queryPlanner.winningPlan));
// .max()
explain = t.explain().find().max({a: 1}).finish();
assert.commandWorked(explain);
-assert(isIxscan(explain.queryPlanner.winningPlan));
+assert(isIxscan(db, explain.queryPlanner.winningPlan));
explain = t.find().max({a: 1}).explain();
assert.commandWorked(explain);
-assert(isIxscan(explain.queryPlanner.winningPlan));
+assert(isIxscan(db, explain.queryPlanner.winningPlan));
// .showDiskLoc()
explain = t.explain().find().showDiskLoc().finish();
@@ -234,7 +234,7 @@ assert("queryPlanner" in explain.stages[0].$cursor);
// Basic count.
explain = t.explain().count();
assert.commandWorked(explain);
-assert(planHasStage(explain.queryPlanner.winningPlan, "COUNT"));
+assert(planHasStage(db, explain.queryPlanner.winningPlan, "COUNT"));
// Tests for applySkipLimit argument to .count. When we don't apply the skip, we
// count one result. When we do apply the skip we count zero.
@@ -254,14 +254,14 @@ assert.eq(0, stage.nCounted);
// Count with hint.
explain = t.explain().find({a: 3}).hint({a: 1}).count();
assert.commandWorked(explain);
-assert(planHasStage(explain.queryPlanner.winningPlan, "COUNT"));
-assert(planHasStage(explain.queryPlanner.winningPlan, "COUNT_SCAN"));
+assert(planHasStage(db, explain.queryPlanner.winningPlan, "COUNT"));
+assert(planHasStage(db, explain.queryPlanner.winningPlan, "COUNT_SCAN"));
// Explainable count with hint.
assert.commandWorked(t.ensureIndex({c: 1}, {sparse: true}));
explain = t.explain().count({c: {$exists: false}}, {hint: "c_1"});
assert.commandWorked(explain);
-assert(planHasStage(explain.queryPlanner.winningPlan, "IXSCAN"));
+assert(planHasStage(db, explain.queryPlanner.winningPlan, "IXSCAN"));
assert.eq(getPlanStage(explain.queryPlanner.winningPlan, "IXSCAN").indexName, "c_1");
assert.commandWorked(t.dropIndex({c: 1}));
@@ -278,17 +278,17 @@ assert.commandWorked(explain);
explain = t.explain().distinct('_id');
assert.commandWorked(explain);
-assert(planHasStage(explain.queryPlanner.winningPlan, "PROJECTION"));
-assert(planHasStage(explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
+assert(planHasStage(db, explain.queryPlanner.winningPlan, "PROJECTION"));
+assert(planHasStage(db, explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
explain = t.explain().distinct('a');
assert.commandWorked(explain);
-assert(planHasStage(explain.queryPlanner.winningPlan, "PROJECTION"));
-assert(planHasStage(explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
+assert(planHasStage(db, explain.queryPlanner.winningPlan, "PROJECTION"));
+assert(planHasStage(db, explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
explain = t.explain().distinct('b');
assert.commandWorked(explain);
-assert(planHasStage(explain.queryPlanner.winningPlan, "COLLSCAN"));
+assert(planHasStage(db, explain.queryPlanner.winningPlan, "COLLSCAN"));
//
// .remove()
diff --git a/jstests/core/find1.js b/jstests/core/find1.js
index a09c0822a47..e43b54dd398 100644
--- a/jstests/core/find1.js
+++ b/jstests/core/find1.js
@@ -1,6 +1,8 @@
+// This test makes assumptions about the order of collection scans using the snapshot query option.
+// This order can change when the collection is sharded.
+// @tags: [assumes_unsharded_collection]
t = db.find1;
t.drop();
-
lookAtDocumentMetrics = false;
// QUERY MIGRATION
diff --git a/jstests/core/find5.js b/jstests/core/find5.js
index 633b723fe5a..1771c1fbbdb 100644
--- a/jstests/core/find5.js
+++ b/jstests/core/find5.js
@@ -10,7 +10,7 @@
assert.eq(2, coll.find({}, {b: 1}).count(), "A");
function getIds(projection) {
- return coll.find({}, projection).map(doc => doc._id);
+ return coll.find({}, projection).map(doc => doc._id).sort();
}
assert.eq(Array.tojson(getIds(null)), Array.tojson(getIds({})), "B1 ");
diff --git a/jstests/core/fts_mix.js b/jstests/core/fts_mix.js
index f0098639e87..89195d8b710 100644
--- a/jstests/core/fts_mix.js
+++ b/jstests/core/fts_mix.js
@@ -1,5 +1,6 @@
load("jstests/libs/fts.js");
+load("jstests/aggregation/extras/utils.js"); // For resultsEq.
// test collection
tc = db.text_mix;
@@ -84,19 +85,19 @@ tc.dropIndexes();
// now let's see about multiple fields, with specific weighting
tc.ensureIndex({"title": "text", "text": "text"}, {weights: {"title": 10}});
-assert.eq([9, 7, 8], queryIDS(tc, "members physics"));
+assert(resultsEq([9, 7, 8], queryIDS(tc, "members physics")));
tc.dropIndexes();
// test all-1 weighting with "$**"
tc.ensureIndex({"$**": "text"});
-assert.eq([2, 8, 7], queryIDS(tc, "family tea estate"));
+assert(resultsEq([2, 8, 7], queryIDS(tc, "family tea estate")));
tc.dropIndexes();
// non-1 weight on "$**" + other weight specified for some field
tc.ensureIndex({"$**": "text"}, {weights: {"$**": 10, "text": 2}});
-assert.eq([7, 5], queryIDS(tc, "Olympic Games gold medal"));
+assert(resultsEq([7, 5], queryIDS(tc, "Olympic Games gold medal")));
tc.dropIndexes();
@@ -111,12 +112,12 @@ tc.ensureIndex({"$**": "text"}, {weights: {"title": 10}});
// tests stemming for basic plural case
res = tc.find({"$text": {"$search": "member"}});
res2 = tc.find({"$text": {"$search": "members"}});
-assert.eq(getIDS(res), getIDS(res2));
+assert(resultsEq(getIDS(res), getIDS(res2)));
// "search" for something with potential 's bug.
res = tc.find({"$text": {"$search": "magazine's"}});
res2 = tc.find({"$text": {"$search": "magazine"}});
-assert.eq(getIDS(res), getIDS(res2));
+assert(resultsEq(getIDS(res), getIDS(res2)));
// -------------------------------------------- LANGUAGE -------------------------------------------
@@ -152,13 +153,10 @@ assert.doesNotThrow(function() {
// ensure limit limits results
assert.eq([2], queryIDS(tc, "rural river dam", null, null, 1));
-// ensure top results are the same regardless of limit
-// make sure that this uses a case where it wouldn't be otherwise..
res = tc.find({"$text": {"$search": "united kingdom british princes"}}).limit(1);
-res2 = tc.find({"$text": {"$search": "united kingdom british princes"}});
assert.eq(1, res.length());
+res2 = tc.find({"$text": {"$search": "united kingdom british princes"}});
assert.eq(4, res2.length());
-assert.eq(res[0]._id, res2[0]._id);
// -------------------------------------------- PROJECTION -----------------------------------------
@@ -226,7 +224,3 @@ assert.eq([2], queryIDS(tc, "Mahim", {_id: {$lte: 4}}));
// using regex conditional filtering
assert.eq([9], queryIDS(tc, "members", {title: {$regex: /Phy.*/i}}));
-
-// -------------------------------------------------------------------------------------------------
-
-assert(tc.validate().valid);
diff --git a/jstests/core/fts_projection.js b/jstests/core/fts_projection.js
index 0942c7563b9..f6b4773c2da 100644
--- a/jstests/core/fts_projection.js
+++ b/jstests/core/fts_projection.js
@@ -114,10 +114,10 @@ assert.neq(-1,
let explainOutput = t.find({$text: {$search: "textual content -irrelevant"}}, {
score: {$meta: "textScore"}
}).explain();
-assert(planHasStage(explainOutput.queryPlanner.winningPlan, "TEXT_OR"));
+assert(planHasStage(db, explainOutput.queryPlanner.winningPlan, "TEXT_OR"));
explainOutput = t.find({$text: {$search: "textual content -irrelevant"}}).explain();
-assert(!planHasStage(explainOutput.queryPlanner.winningPlan, "TEXT_OR"));
+assert(!planHasStage(db, explainOutput.queryPlanner.winningPlan, "TEXT_OR"));
// Scores should exist.
assert.eq(results.length, 2);
diff --git a/jstests/core/getmore_invalidated_cursors.js b/jstests/core/getmore_invalidated_cursors.js
index 527b6bf81e7..adf9b17fcd5 100644
--- a/jstests/core/getmore_invalidated_cursors.js
+++ b/jstests/core/getmore_invalidated_cursors.js
@@ -5,11 +5,12 @@
(function() {
'use strict';
+ load('jstests/libs/fixture_helpers.js'); // For FixtureHelpers.
+
const testDB = db.getSiblingDB("getmore_invalidated_cursors");
const coll = testDB.test;
const nDocs = 100;
- const batchSize = nDocs - 1;
function setupCollection() {
coll.drop();
@@ -25,6 +26,10 @@
// code and message.
setupCollection();
+ // Make sure the batch size is small enough to ensure a getMore will need to be sent to at least
+ // one shard.
+ const batchSize = (nDocs / FixtureHelpers.numberOfShardsForCollection(coll)) - 1;
+
const isShardedCollection = coll.stats().sharded;
const shellReadMode = testDB.getMongo().readMode();
diff --git a/jstests/core/hashindex1.js b/jstests/core/hashindex1.js
index 2e05f9fe3da..b79deeee445 100644
--- a/jstests/core/hashindex1.js
+++ b/jstests/core/hashindex1.js
@@ -42,7 +42,7 @@ assert.eq(t.find({a: 3.1}).hint(goodspec).toArray()[0].a, 3.1);
// Make sure we're using the hashed index.
var explain = t.find({a: 1}).explain();
-assert(isIxscan(explain.queryPlanner.winningPlan), "not using hashed index");
+assert(isIxscan(db, explain.queryPlanner.winningPlan), "not using hashed index");
// SERVER-12222
// printjson( t.find({a : {$gte : 3 , $lte : 3}}).explain() )
@@ -50,20 +50,20 @@ assert(isIxscan(explain.queryPlanner.winningPlan), "not using hashed index");
// cursorname ,
// "not using hashed cursor");
var explain = t.find({c: 1}).explain();
-assert(!isIxscan(explain.queryPlanner.winningPlan), "using irrelevant hashed index");
+assert(!isIxscan(db, explain.queryPlanner.winningPlan), "using irrelevant hashed index");
// Hash index used with a $in set membership predicate.
var explain = t.find({a: {$in: [1, 2]}}).explain();
printjson(explain);
-assert(isIxscan(explain.queryPlanner.winningPlan), "not using hashed index");
+assert(isIxscan(db, explain.queryPlanner.winningPlan), "not using hashed index");
// Hash index used with a singleton $and predicate conjunction.
var explain = t.find({$and: [{a: 1}]}).explain();
-assert(isIxscan(explain.queryPlanner.winningPlan), "not using hashed index");
+assert(isIxscan(db, explain.queryPlanner.winningPlan), "not using hashed index");
// Hash index used with a non singleton $and predicate conjunction.
var explain = t.find({$and: [{a: {$in: [1, 2]}}, {a: {$gt: 1}}]}).explain();
-assert(isIxscan(explain.queryPlanner.winningPlan), "not using hashed index");
+assert(isIxscan(db, explain.queryPlanner.winningPlan), "not using hashed index");
// test creation of index based on hash of _id index
var goodspec2 = {'_id': "hashed"};
diff --git a/jstests/core/idhack.js b/jstests/core/idhack.js
index 0855a8ccbeb..2ef3041c759 100644
--- a/jstests/core/idhack.js
+++ b/jstests/core/idhack.js
@@ -31,23 +31,23 @@ var explain = t.find(query).explain(true);
print("explain for " + tojson(query, "", true) + " = " + tojson(explain));
assert.eq(1, explain.executionStats.nReturned, "D1");
assert.eq(1, explain.executionStats.totalKeysExamined, "D2");
-assert(isIdhack(explain.queryPlanner.winningPlan), "D3");
+assert(isIdhack(db, explain.queryPlanner.winningPlan), "D3");
// ID hack cannot be used with hint().
t.ensureIndex({_id: 1, a: 1});
var hintExplain = t.find(query).hint({_id: 1, a: 1}).explain();
print("explain for hinted query = " + tojson(hintExplain));
-assert(!isIdhack(hintExplain.queryPlanner.winningPlan), "E1");
+assert(!isIdhack(db, hintExplain.queryPlanner.winningPlan), "E1");
// ID hack cannot be used with skip().
var skipExplain = t.find(query).skip(1).explain();
print("explain for skip query = " + tojson(skipExplain));
-assert(!isIdhack(skipExplain.queryPlanner.winningPlan), "F1");
+assert(!isIdhack(db, skipExplain.queryPlanner.winningPlan), "F1");
// Covered query returning _id field only can be handled by ID hack.
var coveredExplain = t.find(query, {_id: 1}).explain();
print("explain for covered query = " + tojson(coveredExplain));
-assert(isIdhack(coveredExplain.queryPlanner.winningPlan), "G1");
+assert(isIdhack(db, coveredExplain.queryPlanner.winningPlan), "G1");
// Check doc from covered ID hack query.
assert.eq({_id: {x: 2}}, t.findOne(query, {_id: 1}), "G2");
diff --git a/jstests/core/indexOtherNamespace.js b/jstests/core/indexOtherNamespace.js
index f5919f721e8..86589714a35 100644
--- a/jstests/core/indexOtherNamespace.js
+++ b/jstests/core/indexOtherNamespace.js
@@ -8,12 +8,12 @@ otherDB.dropDatabase();
otherDB.foo.insert({a: 1});
assert.eq(1, otherDB.foo.getIndexes().length);
-assert(isCollscan(otherDB.foo.find({a: 1}).explain().queryPlanner.winningPlan));
+assert(isCollscan(db, otherDB.foo.find({a: 1}).explain().queryPlanner.winningPlan));
assert.writeError(
otherDB.randomNS.system.indexes.insert({ns: "indexOtherNS.foo", key: {a: 1}, name: "a_1"}));
// Assert that index didn't actually get built
assert.eq(1, otherDB.foo.getIndexes().length);
-assert(isCollscan(otherDB.foo.find({a: 1}).explain().queryPlanner.winningPlan));
+assert(isCollscan(db, otherDB.foo.find({a: 1}).explain().queryPlanner.winningPlan));
otherDB.dropDatabase();
diff --git a/jstests/core/index_bounds_pipe.js b/jstests/core/index_bounds_pipe.js
index e284d5c78f3..ee6cbd5b5f7 100644
--- a/jstests/core/index_bounds_pipe.js
+++ b/jstests/core/index_bounds_pipe.js
@@ -31,13 +31,17 @@
const explain = db.runCommand({explain: command});
assert.commandWorked(explain);
- // Check that the query uses correct index bounds.
- const ixscan = getPlanStage(explain.queryPlanner.winningPlan, 'IXSCAN');
- assert.neq(ixscan, null, 'Plan unexpectedly missing IXSCAN stage: ' + tojson(explain));
- assert.eq(ixscan.indexBounds._id,
- params.bounds,
- 'Expected bounds of ' + tojson(params.bounds) + ' but got ' +
- tojson(ixscan.indexBounds._id));
+ // Check that the query uses correct index bounds. When run against a sharded cluster, there
+ // may be multiple index scan stages, but each should have the same index bounds.
+ const ixscans = getPlanStages(explain.queryPlanner.winningPlan, 'IXSCAN');
+ assert.gt(ixscans.length, 0, 'Plan unexpectedly missing IXSCAN stage: ' + tojson(explain));
+ for (let i = 0; i < ixscans.length; i++) {
+ const ixscan = ixscans[i];
+ assert.eq(ixscan.indexBounds._id,
+ params.bounds,
+ `Expected bounds of ${tojson(params.bounds)} but got ${
+ tojson(ixscan.indexBounds._id)}. i=${i}, all output: ${tojson(explain)}`);
+ }
// Check that the query regex matches expected strings.
const results = db.runCommand(command);
diff --git a/jstests/core/index_bounds_timestamp.js b/jstests/core/index_bounds_timestamp.js
index 8acb842869a..a0114f2a4e3 100644
--- a/jstests/core/index_bounds_timestamp.js
+++ b/jstests/core/index_bounds_timestamp.js
@@ -10,8 +10,14 @@
// Helper function to get the nCounted from the COUNT stage in an explain plan's executionStats.
function getCountFromExecutionStats(executionStats) {
let stages = getPlanStages(executionStats.executionStages, "COUNT");
- assert.eq(1, stages.length, "executionStats should have 1 COUNT stage");
- return stages[0].nCounted;
+ // In a sharded cluster, there may be multiple COUNT stages. The sum of the 'nCounted'
+ // fields is what we're interested in here.
+ assert.gte(stages.length, 1, "executionStats should have at least 1 COUNT stage");
+ let totalCounted = 0;
+ stages.forEach(function(countStage) {
+ totalCounted += countStage.nCounted;
+ });
+ return totalCounted;
}
// Setup the test collection.
@@ -38,19 +44,21 @@
// Check that count over (Timestamp(0, 0), Timestamp(2^32 - 1, 2^32 - 1)] is a covered query.
plan = coll.explain("executionStats").find({ts: {$gt: Timestamp(0, 0)}}).count();
- assert(isIndexOnly(plan.queryPlanner.winningPlan), "ts $gt count should be a covered query");
+ assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
+ "ts $gt count should be a covered query");
assert.eq(5, getCountFromExecutionStats(plan.executionStats), "ts $gt count should be 5");
// Check that find over (Timestamp(0, 0), Timestamp(2^32 - 1, 2^32 - 1)] does not require a
// FETCH stage when the query is covered by an index.
plan =
coll.explain("executionStats").find({ts: {$gt: Timestamp(0, 0)}}, {ts: 1, _id: 0}).finish();
- assert(isIndexOnly(plan.queryPlanner.winningPlan),
+ assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"ts $gt find with project should be a covered query");
// Check that count over [Timestamp(0, 0), Timestamp(2^32 - 1, 2^32 - 1)] is a covered query.
plan = coll.explain("executionStats").find({ts: {$gte: Timestamp(0, 0)}}).count();
- assert(isIndexOnly(plan.queryPlanner.winningPlan), "ts $gte count should be a covered query");
+ assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
+ "ts $gte count should be a covered query");
assert.eq(5, getCountFromExecutionStats(plan.executionStats), "ts $gte count should be 5");
// Check that find over [Timestamp(0, 0), Timestamp(2^32 - 1, 2^32 - 1)] does not require a
@@ -58,24 +66,26 @@
plan = coll.explain("executionStats")
.find({ts: {$gte: Timestamp(0, 0)}}, {ts: 1, _id: 0})
.finish();
- assert(isIndexOnly(plan.queryPlanner.winningPlan),
+ assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"ts $gte find with project should be a covered query");
// Check that count over [Timestamp(0, 0), Timestamp(1, 0)) is a covered query.
plan = coll.explain("executionStats").find({ts: {$lt: Timestamp(1, 0)}}).count();
- assert(isIndexOnly(plan.queryPlanner.winningPlan), "ts $lt count should be a covered query");
+ assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
+ "ts $lt count should be a covered query");
assert.eq(3, getCountFromExecutionStats(plan.executionStats), "ts $lt count should be 3");
// Check that find over [Timestamp(0, 0), Timestamp(1, 0)) does not require a FETCH stage when
// the query is covered by an index.
plan =
coll.explain("executionStats").find({ts: {$lt: Timestamp(1, 0)}}, {ts: 1, _id: 0}).finish();
- assert(isIndexOnly(plan.queryPlanner.winningPlan),
+ assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"ts $lt find with project should be a covered query");
// Check that count over [Timestamp(0, 0), Timestamp(1, 0)] is a covered query.
plan = coll.explain("executionStats").find({ts: {$lte: Timestamp(1, 0)}}).count();
- assert(isIndexOnly(plan.queryPlanner.winningPlan), "ts $lte count should be a covered query");
+ assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
+ "ts $lte count should be a covered query");
assert.eq(4, getCountFromExecutionStats(plan.executionStats), "ts $lte count should be 4");
// Check that find over [Timestamp(0, 0), Timestamp(1, 0)] does not require a FETCH stage when
@@ -83,14 +93,14 @@
plan = coll.explain("executionStats")
.find({ts: {$lte: Timestamp(1, 0)}}, {ts: 1, _id: 0})
.finish();
- assert(isIndexOnly(plan.queryPlanner.winningPlan),
+ assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"ts $lte find with project should be a covered query");
// Check that count over (Timestamp(0, 1), Timestamp(1, 0)) is a covered query.
plan = coll.explain("executionStats")
.find({ts: {$gt: Timestamp(0, 1), $lt: Timestamp(1, 0)}})
.count();
- assert(isIndexOnly(plan.queryPlanner.winningPlan),
+ assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"ts $gt, $lt count should be a covered query");
assert.eq(2, getCountFromExecutionStats(plan.executionStats), "ts $gt, $lt count should be 2");
@@ -99,14 +109,14 @@
plan = coll.explain("executionStats")
.find({ts: {$gt: Timestamp(0, 1), $lt: Timestamp(1, 0)}}, {ts: 1, _id: 0})
.finish();
- assert(isIndexOnly(plan.queryPlanner.winningPlan),
+ assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"ts $gt, $lt find with project should be a covered query");
// Check that count over (Timestamp(0, 1), Timestamp(1, 0)] is a covered query.
plan = coll.explain("executionStats")
.find({ts: {$gt: Timestamp(0, 1), $lte: Timestamp(1, 0)}})
.count();
- assert(isIndexOnly(plan.queryPlanner.winningPlan),
+ assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"ts $gt, $lte count should be a covered query");
assert.eq(3, getCountFromExecutionStats(plan.executionStats), "ts $gt, $lte count should be 3");
@@ -115,14 +125,14 @@
plan = coll.explain("executionStats")
.find({ts: {$gt: Timestamp(0, 1), $lte: Timestamp(1, 0)}}, {ts: 1, _id: 0})
.finish();
- assert(isIndexOnly(plan.queryPlanner.winningPlan),
+ assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"ts $gt, $lte find with project should be a covered query");
// Check that count over [Timestamp(0, 1), Timestamp(1, 0)) is a covered query.
plan = coll.explain("executionStats")
.find({ts: {$gte: Timestamp(0, 1), $lt: Timestamp(1, 0)}})
.count();
- assert(isIndexOnly(plan.queryPlanner.winningPlan),
+ assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"ts $gte, $lt count should be a covered query");
assert.eq(3, getCountFromExecutionStats(plan.executionStats), "ts $gte, $lt count should be 3");
@@ -131,14 +141,14 @@
plan = coll.explain("executionStats")
.find({ts: {$gte: Timestamp(0, 1), $lt: Timestamp(1, 0)}}, {ts: 1, _id: 0})
.finish();
- assert(isIndexOnly(plan.queryPlanner.winningPlan),
+ assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"ts $gte, $lt find with project should be a covered query");
// Check that count over [Timestamp(0, 1), Timestamp(1, 0)] is a covered query.
plan = coll.explain("executionStats")
.find({ts: {$gte: Timestamp(0, 1), $lte: Timestamp(1, 0)}})
.count();
- assert(isIndexOnly(plan.queryPlanner.winningPlan),
+ assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"ts $gte, $lte count should be a covered query");
assert.eq(
4, getCountFromExecutionStats(plan.executionStats), "ts $gte, $lte count should be 4");
@@ -148,6 +158,6 @@
plan = coll.explain("executionStats")
.find({ts: {$gte: Timestamp(0, 1), $lte: Timestamp(1, 0)}}, {ts: 1, _id: 0})
.finish();
- assert(isIndexOnly(plan.queryPlanner.winningPlan),
+ assert(isIndexOnly(db, plan.queryPlanner.winningPlan),
"ts $gte, $lte find with project should be a covered query");
})();
diff --git a/jstests/core/index_check2.js b/jstests/core/index_check2.js
index 534784e6579..027cbf50ba9 100644
--- a/jstests/core/index_check2.js
+++ b/jstests/core/index_check2.js
@@ -35,9 +35,9 @@ assert.eq(120, t.find(q2).itcount(), "q2 a");
assert.eq(60, t.find(q3).itcount(), "q3 a");
// We expect these queries to use index scans over { tags: 1 }.
-assert(isIxscan(t.find(q1).explain().queryPlanner.winningPlan), "e1");
-assert(isIxscan(t.find(q2).explain().queryPlanner.winningPlan), "e2");
-assert(isIxscan(t.find(q3).explain().queryPlanner.winningPlan), "e3");
+assert(isIxscan(db, t.find(q1).explain().queryPlanner.winningPlan), "e1");
+assert(isIxscan(db, t.find(q2).explain().queryPlanner.winningPlan), "e2");
+assert(isIxscan(db, t.find(q3).explain().queryPlanner.winningPlan), "e3");
scanned1 = t.find(q1).explain("executionStats").executionStats.totalKeysExamined;
scanned2 = t.find(q2).explain("executionStats").executionStats.totalKeysExamined;
diff --git a/jstests/core/index_check6.js b/jstests/core/index_check6.js
index e85913aeec3..fd4a7177ffb 100644
--- a/jstests/core/index_check6.js
+++ b/jstests/core/index_check6.js
@@ -1,4 +1,6 @@
-
+// This test makes assertions about how many keys are examined during query execution, which can
+// change depending on whether/how many documents are filtered out by the SHARDING_FILTER stage.
+// @tags: [assumes_unsharded_collection]
t = db.index_check6;
t.drop();
diff --git a/jstests/core/index_decimal.js b/jstests/core/index_decimal.js
index 312ab106674..1fbb62332a2 100644
--- a/jstests/core/index_decimal.js
+++ b/jstests/core/index_decimal.js
@@ -38,7 +38,7 @@
assert.eq(qres,
[{x: NumberDecimal('0.10')}],
'query for x equal to decimal 0.10 returns wrong value');
- assert(isIndexOnly(qplan.queryPlanner.winningPlan),
+ assert(isIndexOnly(db, qplan.queryPlanner.winningPlan),
'query on decimal should be covered: ' + tojson(qplan));
// Check that queries for exact floating point numbers don't return nearby decimals.
diff --git a/jstests/core/index_diag.js b/jstests/core/index_diag.js
index e458a590dda..3779d5f3c78 100644
--- a/jstests/core/index_diag.js
+++ b/jstests/core/index_diag.js
@@ -1,8 +1,9 @@
+load("jstests/libs/fixture_helpers.js");
t = db.index_diag;
t.drop();
-t.ensureIndex({x: 1});
+assert.commandWorked(t.createIndex({x: 1}));
all = [];
ids = [];
@@ -23,22 +24,28 @@ for (i = 1; i < 4; i++) {
xs.push({x: -i});
}
-assert.eq(all, t.find().sort({_id: 1}).toArray(), "A1");
-assert.eq(r(all), t.find().sort({_id: -1}).toArray(), "A2");
+assert.eq(all, t.find().sort({_id: 1}).toArray());
+assert.eq(r(all), t.find().sort({_id: -1}).toArray());
-assert.eq(all, t.find().sort({x: -1}).toArray(), "A3");
-assert.eq(r(all), t.find().sort({x: 1}).toArray(), "A4");
+assert.eq(all, t.find().sort({x: -1}).toArray());
+assert.eq(r(all), t.find().sort({x: 1}).toArray());
-assert.eq(ids, t.find().sort({_id: 1}).returnKey().toArray(), "B1");
-assert.eq(r(ids), t.find().sort({_id: -1}).returnKey().toArray(), "B2");
-assert.eq(xs, t.find().sort({x: -1}).returnKey().toArray(), "B3");
-assert.eq(r(xs), t.find().sort({x: 1}).returnKey().toArray(), "B4");
-
-assert.eq(r(xs), t.find().hint({x: 1}).returnKey().toArray(), "B4");
+assert.eq(ids, t.find().sort({_id: 1}).returnKey().toArray());
+assert.eq(r(ids), t.find().sort({_id: -1}).returnKey().toArray());
+assert.eq(xs, t.find().sort({x: -1}).returnKey().toArray());
+assert.eq(r(xs), t.find().sort({x: 1}).returnKey().toArray());
// SERVER-4981
-t.ensureIndex({_id: 1, x: 1});
-assert.eq(all, t.find().hint({_id: 1, x: 1}).returnKey().toArray());
+if (FixtureHelpers.numberOfShardsForCollection(t) === 1) {
+ // With only one shard we can reliably assert on the order of results with a hint, since they
+ // will come straight off the index. However, without a sort specified, we cannot make this
+ // assertion when there are multiple shards, since mongos can merge results from each shard in
+ // whatever order it likes.
+ assert.eq(r(xs), t.find().hint({x: 1}).returnKey().toArray());
+ assert.commandWorked(t.createIndex({_id: 1, x: 1}));
+ assert.eq(all, t.find().hint({_id: 1, x: 1}).returnKey().toArray());
+}
+assert.commandWorked(t.ensureIndex({_id: 1, x: 1}));
assert.eq(r(all), t.find().hint({_id: 1, x: 1}).sort({x: 1}).returnKey().toArray());
assert.eq([{}, {}, {}], t.find().hint({$natural: 1}).returnKey().toArray());
diff --git a/jstests/core/index_elemmatch2.js b/jstests/core/index_elemmatch2.js
index ecd24035284..d87b26e7642 100644
--- a/jstests/core/index_elemmatch2.js
+++ b/jstests/core/index_elemmatch2.js
@@ -19,7 +19,7 @@
function assertIndexResults(coll, query, useIndex, nReturned) {
const explainPlan = coll.find(query).explain("executionStats");
- assert.eq(isIxscan(explainPlan.queryPlanner.winningPlan), useIndex);
+ assert.eq(isIxscan(db, explainPlan.queryPlanner.winningPlan), useIndex);
assert.eq(explainPlan.executionStats.nReturned, nReturned);
}
diff --git a/jstests/core/index_filter_commands.js b/jstests/core/index_filter_commands.js
index cc50f65ca39..aefc40c72de 100644
--- a/jstests/core/index_filter_commands.js
+++ b/jstests/core/index_filter_commands.js
@@ -222,10 +222,10 @@ assert.commandWorked(t.runCommand('planCacheSetFilter',
// pattern.
explain = t.find(queryAA).explain();
-assert(isIxscan(explain.queryPlanner.winningPlan), "Expected index scan: " + tojson(explain));
+assert(isIxscan(db, explain.queryPlanner.winningPlan), "Expected index scan: " + tojson(explain));
explain = t.find(queryAA).collation(collationEN).explain();
-assert(isIxscan(explain.queryPlanner.winningPlan), "Expected index scan: " + tojson(explain));
+assert(isIxscan(db, explain.queryPlanner.winningPlan), "Expected index scan: " + tojson(explain));
// Ensure that index names in planCacheSetFilter only select matching names.
@@ -233,7 +233,7 @@ assert.commandWorked(
t.runCommand('planCacheSetFilter', {query: queryAA, collation: collationEN, indexes: ["a_1"]}));
explain = t.find(queryAA).collation(collationEN).explain();
-assert(isCollscan(explain.queryPlanner.winningPlan), "Expected collscan: " + tojson(explain));
+assert(isCollscan(db, explain.queryPlanner.winningPlan), "Expected collscan: " + tojson(explain));
//
// Test that planCacheSetFilter and planCacheClearFilters allow queries containing $expr.
diff --git a/jstests/core/index_partial_read_ops.js b/jstests/core/index_partial_read_ops.js
index fc8ab0233a7..f06ee85c621 100644
--- a/jstests/core/index_partial_read_ops.js
+++ b/jstests/core/index_partial_read_ops.js
@@ -24,21 +24,21 @@ load("jstests/libs/analyze_plan.js");
// find() operations that should use index.
explain = coll.explain('executionStats').find({x: 6, a: 1}).finish();
assert.eq(1, explain.executionStats.nReturned);
- assert(isIxscan(explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, explain.queryPlanner.winningPlan));
explain = coll.explain('executionStats').find({x: {$gt: 1}, a: 1}).finish();
assert.eq(1, explain.executionStats.nReturned);
- assert(isIxscan(explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, explain.queryPlanner.winningPlan));
explain = coll.explain('executionStats').find({x: 6, a: {$lte: 1}}).finish();
assert.eq(1, explain.executionStats.nReturned);
- assert(isIxscan(explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, explain.queryPlanner.winningPlan));
// find() operations that should not use index.
explain = coll.explain('executionStats').find({x: 6, a: {$lt: 1.6}}).finish();
assert.eq(1, explain.executionStats.nReturned);
- assert(isCollscan(explain.queryPlanner.winningPlan));
+ assert(isCollscan(db, explain.queryPlanner.winningPlan));
explain = coll.explain('executionStats').find({x: 6}).finish();
assert.eq(1, explain.executionStats.nReturned);
- assert(isCollscan(explain.queryPlanner.winningPlan));
+ assert(isCollscan(db, explain.queryPlanner.winningPlan));
//
// Verify basic functionality with the count command.
@@ -46,11 +46,11 @@ load("jstests/libs/analyze_plan.js");
// Count operation that should use index.
explain = coll.explain('executionStats').count({x: {$gt: 1}, a: 1});
- assert(isIxscan(explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, explain.queryPlanner.winningPlan));
// Count operation that should not use index.
explain = coll.explain('executionStats').count({x: {$gt: 1}, a: 2});
- assert(isCollscan(explain.queryPlanner.winningPlan));
+ assert(isCollscan(db, explain.queryPlanner.winningPlan));
//
// Verify basic functionality with the aggregate command.
@@ -58,11 +58,11 @@ load("jstests/libs/analyze_plan.js");
// Aggregate operation that should use index.
explain = coll.aggregate([{$match: {x: {$gt: 1}, a: 1}}], {explain: true}).stages[0].$cursor;
- assert(isIxscan(explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, explain.queryPlanner.winningPlan));
// Aggregate operation that should not use index.
explain = coll.aggregate([{$match: {x: {$gt: 1}, a: 2}}], {explain: true}).stages[0].$cursor;
- assert(isCollscan(explain.queryPlanner.winningPlan));
+ assert(isCollscan(db, explain.queryPlanner.winningPlan));
//
// Verify basic functionality with the findAndModify command.
@@ -72,11 +72,11 @@ load("jstests/libs/analyze_plan.js");
explain = coll.explain('executionStats')
.findAndModify({query: {x: {$gt: 1}, a: 1}, update: {$inc: {x: 1}}});
assert.eq(1, explain.executionStats.nReturned);
- assert(isIxscan(explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, explain.queryPlanner.winningPlan));
// findAndModify operation that should not use index.
explain = coll.explain('executionStats')
.findAndModify({query: {x: {$gt: 1}, a: 2}, update: {$inc: {x: 1}}});
assert.eq(1, explain.executionStats.nReturned);
- assert(isCollscan(explain.queryPlanner.winningPlan));
+ assert(isCollscan(db, explain.queryPlanner.winningPlan));
})();
diff --git a/jstests/core/index_type_change.js b/jstests/core/index_type_change.js
index 37e1d4c06e3..ad2525fe015 100644
--- a/jstests/core/index_type_change.js
+++ b/jstests/core/index_type_change.js
@@ -34,7 +34,7 @@ load("jstests/libs/analyze_plan.js"); // For 'isIndexOnly'.
// First make sure it's actually using a covered index scan.
var explain = coll.explain().find({a: 2}, {_id: 0, a: 1});
- assert(isIndexOnly(explain));
+ assert(isIndexOnly(db, explain));
var updated = coll.findOne({a: 2}, {_id: 0, a: 1});
diff --git a/jstests/core/indexj.js b/jstests/core/indexj.js
index 01754466a3a..4236ce0a535 100644
--- a/jstests/core/indexj.js
+++ b/jstests/core/indexj.js
@@ -1,4 +1,7 @@
// SERVER-726
+// This test makes assertions about how many keys are examined during query execution, which can
+// change depending on whether/how many documents are filtered out by the SHARDING_FILTER stage.
+// @tags: [assumes_unsharded_collection]
t = db.jstests_indexj;
t.drop();
diff --git a/jstests/core/maxscan.js b/jstests/core/maxscan.js
index 37cbf4b5b2f..c8ba77b1173 100644
--- a/jstests/core/maxscan.js
+++ b/jstests/core/maxscan.js
@@ -1,6 +1,8 @@
(function() {
"use strict";
+ load("jstests/libs/fixture_helpers.js"); // For FixtureHelpers.
+
const coll = db.maxscan;
coll.drop();
@@ -9,13 +11,17 @@
assert.writeOK(coll.insert({_id: i, x: i % 10}));
}
- assert.eq(N, coll.find().itcount(), "A");
- assert.eq(50, coll.find().maxScan(50).itcount(), "B");
+ assert.eq(N, coll.find().itcount());
+ // We should scan no more than 50 things on each shard.
+ assert.lte(coll.find().maxScan(50).itcount(),
+ 50 * FixtureHelpers.numberOfShardsForCollection(coll));
- assert.eq(10, coll.find({x: 2}).itcount(), "C");
- assert.eq(5, coll.find({x: 2}).sort({_id: 1}).maxScan(50).itcount(), "D");
+ assert.eq(coll.find({x: 2}).itcount(), 10);
+ // We should scan no more than 50 things on each shard.
+ assert.lte(coll.find({x: 2}).sort({_id: 1}).maxScan(50).itcount(),
+ 5 * FixtureHelpers.numberOfShardsForCollection(coll));
assert.commandWorked(coll.ensureIndex({x: 1}));
- assert.eq(10, coll.find({x: 2}).sort({_id: 1}).hint({x: 1}).maxScan(N).itcount(), "E");
- assert.eq(0, coll.find({x: 2}).sort({_id: 1}).hint({x: 1}).maxScan(1).itcount(), "E");
+ assert.eq(coll.find({x: 2}).sort({_id: 1}).hint({x: 1}).maxScan(N).itcount(), 10);
+ assert.eq(coll.find({x: 2}).sort({_id: 1}).hint({x: 1}).maxScan(1).itcount(), 0);
}());
diff --git a/jstests/core/min_max_bounds.js b/jstests/core/min_max_bounds.js
index 0139ec39851..1e4a80efbf6 100644
--- a/jstests/core/min_max_bounds.js
+++ b/jstests/core/min_max_bounds.js
@@ -3,6 +3,10 @@
*/
(function() {
'use strict';
+
+ load('jstests/libs/fixture_helpers.js'); // For FixtureHelpers.
+ load('jstests/aggregation/extras/utils.js'); // For resultsEq.
+
var coll = db.query_bound_inclusion;
coll.drop();
assert.writeOK(coll.insert({a: 1, b: 1}));
@@ -25,8 +29,14 @@
res = coll.find().min({a: 1}).max({a: 3}).toArray();
assert.eq(res.length, 2);
- assert.eq(res[0].a, 1);
- assert.eq(res[1].a, 2);
+ if (FixtureHelpers.numberOfShardsForCollection(coll) === 1) {
+ assert.eq(res[0].a, 1);
+ assert.eq(res[1].a, 2);
+ } else {
+ // With more than one shard, we cannot assume the results will come back in order, since we
+ // did not request a sort.
+ assert(resultsEq(res.map((result) => result.a), [1, 2]));
+ }
res = coll.find().min({a: 1}).max({a: 3}).sort({a: -1}).toArray();
assert.eq(res.length, 2);
@@ -49,11 +59,17 @@
res = coll.find().min({b: 3}).max({b: 1}).toArray();
assert.eq(res.length, 2);
- assert.eq(res[0].b, 3);
- assert.eq(res[1].b, 2);
+ if (FixtureHelpers.numberOfShardsForCollection(coll) === 1) {
+ assert.eq(res[0].b, 3);
+ assert.eq(res[1].b, 2);
+ } else {
+ // With more than one shard, we cannot assume the results will come back in order, since we
+ // did not request a sort.
+ assert(resultsEq(res.map((result) => result.b), [3, 2]));
+ }
res = coll.find().min({b: 3}).max({b: 1}).sort({b: 1}).toArray();
assert.eq(res.length, 2);
assert.eq(res[0].b, 2);
assert.eq(res[1].b, 3);
-})(); \ No newline at end of file
+})();
diff --git a/jstests/core/minmax.js b/jstests/core/minmax.js
index 670c7d2f8b2..0b73142e136 100644
--- a/jstests/core/minmax.js
+++ b/jstests/core/minmax.js
@@ -1,4 +1,6 @@
// test min / max query parameters
+load("jstests/libs/fixture_helpers.js"); // For FixtureHelpers.
+load("jstests/aggregation/extras/utils.js"); // For resultsEq.
addData = function() {
t.save({a: 1, b: 1});
@@ -75,8 +77,14 @@ t.insert({a: 4});
t.insert({a: 5});
var cursor = t.find().min({a: 4});
-assert.eq(4, cursor.next()["a"]);
-assert.eq(5, cursor.next()["a"]);
+if (FixtureHelpers.numberOfShardsForCollection(t) === 1) {
+ assert.eq(4, cursor.next().a);
+ assert.eq(5, cursor.next().a);
+} else {
+ // With more than one shard, we cannot assume the results will come back in order, since we
+ // did not request a sort.
+ assert(resultsEq([cursor.next().a, cursor.next().a], [4, 5]));
+}
assert(!cursor.hasNext());
cursor = t.find().max({a: 4});
@@ -88,8 +96,14 @@ t.dropIndexes();
t.ensureIndex({a: -1});
cursor = t.find().min({a: 4});
-assert.eq(4, cursor.next()["a"]);
-assert.eq(3, cursor.next()["a"]);
+if (FixtureHelpers.numberOfShardsForCollection(t) === 1) {
+ assert.eq(4, cursor.next().a);
+ assert.eq(3, cursor.next().a);
+} else {
+ // With more than one shard, we cannot assume the results will come back in order, since we
+ // did not request a sort.
+ assert(resultsEq([cursor.next().a, cursor.next().a], [4, 3]));
+}
assert(!cursor.hasNext());
cursor = t.find().max({a: 4});
diff --git a/jstests/core/mr5.js b/jstests/core/mr5.js
index 25aa387594a..b0bf29c4478 100644
--- a/jstests/core/mr5.js
+++ b/jstests/core/mr5.js
@@ -1,53 +1,63 @@
// @tags: [does_not_support_stepdowns]
-t = db.mr5;
-t.drop();
-
-t.save({"partner": 1, "visits": 9});
-t.save({"partner": 2, "visits": 9});
-t.save({"partner": 1, "visits": 11});
-t.save({"partner": 1, "visits": 30});
-t.save({"partner": 2, "visits": 41});
-t.save({"partner": 2, "visits": 41});
-
-m = function() {
- emit(this.partner, {stats: [this.visits]});
-};
-
-r = function(k, v) {
- var stats = [];
- var total = 0;
- for (var i = 0; i < v.length; i++) {
- for (var j in v[i].stats) {
- stats.push(v[i].stats[j]);
- total += v[i].stats[j];
+(function() {
+ "use strict";
+
+ load("jstests/aggregation/extras/utils.js"); // For resultsEq.
+
+ const t = db.mr5;
+ t.drop();
+
+ assert.writeOK(t.insert({"partner": 1, "visits": 9}));
+ assert.writeOK(t.insert({"partner": 2, "visits": 9}));
+ assert.writeOK(t.insert({"partner": 1, "visits": 11}));
+ assert.writeOK(t.insert({"partner": 1, "visits": 30}));
+ assert.writeOK(t.insert({"partner": 2, "visits": 41}));
+ assert.writeOK(t.insert({"partner": 2, "visits": 41}));
+
+ let mapper = function() {
+ emit(this.partner, {stats: [this.visits]});
+ };
+
+ const reducer = function(k, v) {
+ var stats = [];
+ var total = 0;
+ for (var i = 0; i < v.length; i++) {
+ for (var j in v[i].stats) {
+ stats.push(v[i].stats[j]);
+ total += v[i].stats[j];
+ }
}
- }
- return {stats: stats, total: total};
-};
-
-res = t.mapReduce(m, r, {out: "mr5_out", scope: {xx: 1}});
-// res.find().forEach( printjson )
-
-z = res.convertToSingleObject();
-assert.eq(2, Object.keySet(z).length, "A1");
-assert.eq([9, 11, 30], z["1"].stats, "A2");
-assert.eq([9, 41, 41], z["2"].stats, "A3");
-
-res.drop();
-
-m = function() {
- var x = "partner";
- var y = "visits";
- emit(this[x], {stats: [this[y]]});
-};
-
-res = t.mapReduce(m, r, {out: "mr5_out", scope: {xx: 1}});
-// res.find().forEach( printjson )
-
-z = res.convertToSingleObject();
-assert.eq(2, Object.keySet(z).length, "B1");
-assert.eq([9, 11, 30], z["1"].stats, "B2");
-assert.eq([9, 41, 41], z["2"].stats, "B3");
-
-res.drop();
+ return {stats: stats, total: total};
+ };
+
+ let res = t.mapReduce(mapper, reducer, {out: "mr5_out", scope: {xx: 1}});
+
+ let resultAsObj = res.convertToSingleObject();
+ assert.eq(2,
+ Object.keySet(resultAsObj).length,
+ `Expected 2 keys ("1" and "2") in object ${tojson(resultAsObj)}`);
+ // Use resultsEq() to avoid any assumptions about order.
+ assert(resultsEq([9, 11, 30], resultAsObj["1"].stats));
+ assert(resultsEq([9, 41, 41], resultAsObj["2"].stats));
+
+ res.drop();
+
+ mapper = function() {
+ var x = "partner";
+ var y = "visits";
+ emit(this[x], {stats: [this[y]]});
+ };
+
+ res = t.mapReduce(mapper, reducer, {out: "mr5_out", scope: {xx: 1}});
+
+ resultAsObj = res.convertToSingleObject();
+ assert.eq(2,
+ Object.keySet(resultAsObj).length,
+ `Expected 2 keys ("1" and "2") in object ${tojson(resultAsObj)}`);
+ // Use resultsEq() to avoid any assumptions about order.
+ assert(resultsEq([9, 11, 30], resultAsObj["1"].stats));
+ assert(resultsEq([9, 41, 41], resultAsObj["2"].stats));
+
+ res.drop();
+}());
diff --git a/jstests/core/mr_stored.js b/jstests/core/mr_stored.js
index 3da288f0259..dd9853f0589 100644
--- a/jstests/core/mr_stored.js
+++ b/jstests/core/mr_stored.js
@@ -1,4 +1,6 @@
-// @tags: [does_not_support_stepdowns, requires_non_retryable_writes]
+// This test expects a function stored in the system.js collection to be available for a map/reduce,
+// which may not be the case if it is implicitly sharded in a passthrough.
+// @tags: [does_not_support_stepdowns, requires_non_retryable_writes, assumes_unsharded_collection]
t = db.mr_stored;
t.drop();
diff --git a/jstests/core/or2.js b/jstests/core/or2.js
index 2624c213fad..93f738a866d 100644
--- a/jstests/core/or2.js
+++ b/jstests/core/or2.js
@@ -47,7 +47,7 @@ doTest = function(index) {
checkArrs([{_id: 0, x: 0, a: 1}], a1);
if (index) {
var explain = t.find({x: 0, $or: [{a: 1}]}).explain();
- assert(isIxscan(explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, explain.queryPlanner.winningPlan));
}
a1b2 = t.find({x: 1, $or: [{a: 1}, {b: 2}]}).toArray();
@@ -55,7 +55,7 @@ doTest = function(index) {
a1b2);
if (index) {
var explain = t.find({x: 0, $or: [{a: 1}]}).explain();
- assert(isIxscan(explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, explain.queryPlanner.winningPlan));
}
/*
diff --git a/jstests/core/or3.js b/jstests/core/or3.js
index 50434965bae..0c831c8987b 100644
--- a/jstests/core/or3.js
+++ b/jstests/core/or3.js
@@ -51,7 +51,7 @@ doTest = function(index) {
checkArrs(t.find({x: 1, a: {$ne: 1}, b: {$ne: 2}}).toArray(), an1bn2);
if (index) {
var explain = t.find({x: 1, $nor: [{a: 1}, {b: 2}]}).explain();
- assert(isIxscan(explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, explain.queryPlanner.winningPlan));
}
an1b2 = t.find({$nor: [{a: 1}], $or: [{b: 2}]}).toArray();
diff --git a/jstests/core/ord.js b/jstests/core/ord.js
index b398c225c6b..640f5de13cc 100644
--- a/jstests/core/ord.js
+++ b/jstests/core/ord.js
@@ -6,22 +6,26 @@
// behavior is changed.
(function() {
+ "use strict";
+
+ load("jstests/libs/fixture_helpers.js"); // For FixtureHelpers.
+
const t = db.jstests_ord;
t.drop();
t.ensureIndex({a: 1});
t.ensureIndex({b: 1});
- for (i = 0; i < 80; ++i) {
+ for (let i = 0; i < 80; ++i) {
t.save({a: 1});
}
- for (i = 0; i < 100; ++i) {
+ for (let i = 0; i < 100; ++i) {
t.save({b: 1});
}
const c = t.find({$or: [{a: 1}, {b: 1}]}).batchSize(100);
- for (i = 0; i < 100; ++i) {
+ for (let i = 0; i < 100; ++i) {
c.next();
}
// At this point, our initial query has ended and there is a client cursor waiting
@@ -32,7 +36,18 @@
// Dropping an index kills all cursors on the indexed namespace, not just those
// cursors using the dropped index.
- assert.throws(function() {
- c.next();
- });
+ if (FixtureHelpers.isMongos(db)) {
+ // mongos may have some data left from a previous batch stored in memory, so it might not
+ // return an error immediately, but it should eventually.
+ assert.soon(function() {
+ try {
+ c.next();
+ return false; // We didn't throw an error yet.
+ } catch (e) {
+ return true;
+ }
+ });
+ } else {
+ assert.throws(() => c.next());
+ }
})();
diff --git a/jstests/core/proj_key1.js b/jstests/core/proj_key1.js
index 916ad8f1139..06e3c255a3f 100644
--- a/jstests/core/proj_key1.js
+++ b/jstests/core/proj_key1.js
@@ -12,8 +12,5 @@ for (i = 0; i < 10; i++) {
t.ensureIndex({a: 1});
-// assert( t.find( {} , { a : 1 , _id : 0 } ).explain().indexOnly , "A4" ); // TODO: need to modify
-// query optimier SERVER-2109
-
-assert.eq(as, t.find({a: {$gte: 0}}, {a: 1, _id: 0}).toArray(), "B1");
-assert.eq(as, t.find({a: {$gte: 0}}, {a: 1, _id: 0}).batchSize(2).toArray(), "B1");
+assert.eq(as, t.find({a: {$gte: 0}}, {a: 1, _id: 0}).sort({a: 1}).toArray());
+assert.eq(as, t.find({a: {$gte: 0}}, {a: 1, _id: 0}).sort({a: 1}).batchSize(2).toArray());
diff --git a/jstests/core/projection_dotted_paths.js b/jstests/core/projection_dotted_paths.js
index 9f7564a147e..a9316d70467 100644
--- a/jstests/core/projection_dotted_paths.js
+++ b/jstests/core/projection_dotted_paths.js
@@ -22,16 +22,16 @@
assert.eq(resultDoc, {a: 1, b: {c: 1, d: 1}, c: 1});
let explain =
coll.find({a: 1}, {_id: 0, a: 1, "b.c": 1, "b.d": 1, c: 1}).explain("queryPlanner");
- assert(isIxscan(explain.queryPlanner.winningPlan));
- assert(isIndexOnly(explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, explain.queryPlanner.winningPlan));
+ assert(isIndexOnly(db, explain.queryPlanner.winningPlan));
// Project a subset of the indexed fields. Verify that the projection is computed correctly and
// that the plan is covered.
resultDoc = coll.findOne({a: 1}, {_id: 0, "b.c": 1, c: 1});
assert.eq(resultDoc, {b: {c: 1}, c: 1});
explain = coll.find({a: 1}, {_id: 0, "b.c": 1, c: 1}).explain("queryPlanner");
- assert(isIxscan(explain.queryPlanner.winningPlan));
- assert(isIndexOnly(explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, explain.queryPlanner.winningPlan));
+ assert(isIndexOnly(db, explain.queryPlanner.winningPlan));
// Project exactly the set of fields in the index but also include _id. Verify that the
// projection is computed correctly and that the plan cannot be covered.
@@ -39,29 +39,29 @@
assert.eq(resultDoc, {_id: 1, a: 1, b: {c: 1, d: 1}, c: 1});
explain = coll.find({a: 1}, {_id: 0, "b.c": 1, c: 1}).explain("queryPlanner");
explain = coll.find({a: 1}, {_id: 1, a: 1, "b.c": 1, "b.d": 1, c: 1}).explain("queryPlanner");
- assert(isIxscan(explain.queryPlanner.winningPlan));
- assert(!isIndexOnly(explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, explain.queryPlanner.winningPlan));
+ assert(!isIndexOnly(db, explain.queryPlanner.winningPlan));
// Project a not-indexed field that exists in the collection. The plan should not be covered.
resultDoc = coll.findOne({a: 1}, {_id: 0, "b.c": 1, "b.e": 1, c: 1});
assert.eq(resultDoc, {b: {c: 1, e: 1}, c: 1});
explain = coll.find({a: 1}, {_id: 0, "b.c": 1, "b.e": 1, c: 1}).explain("queryPlanner");
- assert(isIxscan(explain.queryPlanner.winningPlan));
- assert(!isIndexOnly(explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, explain.queryPlanner.winningPlan));
+ assert(!isIndexOnly(db, explain.queryPlanner.winningPlan));
// Project a not-indexed field that does not exist in the collection. The plan should not be
// covered.
resultDoc = coll.findOne({a: 1}, {_id: 0, "b.c": 1, "b.z": 1, c: 1});
assert.eq(resultDoc, {b: {c: 1}, c: 1});
explain = coll.find({a: 1}, {_id: 0, "b.c": 1, "b.z": 1, c: 1}).explain("queryPlanner");
- assert(isIxscan(explain.queryPlanner.winningPlan));
- assert(!isIndexOnly(explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, explain.queryPlanner.winningPlan));
+ assert(!isIndexOnly(db, explain.queryPlanner.winningPlan));
// Verify that the correct projection is computed with an idhack query.
resultDoc = coll.findOne({_id: 1}, {_id: 0, "b.c": 1, "b.e": 1, c: 1});
assert.eq(resultDoc, {b: {c: 1, e: 1}, c: 1});
explain = coll.find({_id: 1}, {_id: 0, "b.c": 1, "b.e": 1, c: 1}).explain("queryPlanner");
- assert(isIdhack(explain.queryPlanner.winningPlan));
+ assert(isIdhack(db, explain.queryPlanner.winningPlan));
// If we make a dotted path multikey, projections using that path cannot be covered. But
// projections which do not include the multikey path can still be covered.
@@ -70,17 +70,17 @@
resultDoc = coll.findOne({a: 2}, {_id: 0, "b.c": 1, "b.d": 1});
assert.eq(resultDoc, {b: {c: 1, d: [1, 2, 3]}});
explain = coll.find({a: 2}, {_id: 0, "b.c": 1, "b.d": 1}).explain("queryPlanner");
- assert(isIxscan(explain.queryPlanner.winningPlan));
- assert(!isIndexOnly(explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, explain.queryPlanner.winningPlan));
+ assert(!isIndexOnly(db, explain.queryPlanner.winningPlan));
resultDoc = coll.findOne({a: 2}, {_id: 0, "b.c": 1});
assert.eq(resultDoc, {b: {c: 1}});
explain = coll.find({a: 2}, {_id: 0, "b.c": 1}).explain("queryPlanner");
- assert(isIxscan(explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, explain.queryPlanner.winningPlan));
if (jsTest.options().storageEngine !== "mmapv1") {
// Storage engines other than MMAPv1 track path-level multikey info, and can use this info
// to generate a covered plan.
- assert(isIndexOnly(explain.queryPlanner.winningPlan));
+ assert(isIndexOnly(db, explain.queryPlanner.winningPlan));
}
// Verify that dotted projections work for multiple levels of nesting.
@@ -89,8 +89,8 @@
resultDoc = coll.findOne({a: 3}, {_id: 0, "x.y.y": 1, "x.y.z": 1, "x.z": 1});
assert.eq(resultDoc, {x: {y: {y: 1, z: 1}, z: 1}});
explain = coll.find({a: 3}, {_id: 0, "x.y.y": 1, "x.y.z": 1, "x.z": 1}).explain("queryPlanner");
- assert(isIxscan(explain.queryPlanner.winningPlan));
- assert(isIndexOnly(explain.queryPlanner.winningPlan));
+ assert(isIxscan(db, explain.queryPlanner.winningPlan));
+ assert(isIndexOnly(db, explain.queryPlanner.winningPlan));
// If projected nested paths do not exist in the indexed document, then they will get filled in
// with nulls. This is a bug tracked by SERVER-23229.
diff --git a/jstests/core/record_store_count.js b/jstests/core/record_store_count.js
index aae198fc03e..2b8a9ad71f0 100644
--- a/jstests/core/record_store_count.js
+++ b/jstests/core/record_store_count.js
@@ -20,23 +20,23 @@ load("jstests/libs/analyze_plan.js"); // For 'planHasStage'.
// Logically empty predicates should use the record store's count.
//
var explain = coll.explain().count({});
- assert(!planHasStage(explain.queryPlanner.winningPlan, "COLLSCAN"));
+ assert(!planHasStage(db, explain.queryPlanner.winningPlan, "COLLSCAN"));
explain = coll.explain().count({$comment: "hi"});
- assert(!planHasStage(explain.queryPlanner.winningPlan, "COLLSCAN"));
+ assert(!planHasStage(db, explain.queryPlanner.winningPlan, "COLLSCAN"));
//
// A non-empty query predicate should prevent the use of the record store's count.
//
explain = coll.explain().find({x: 0}).count();
- assert(planHasStage(explain.queryPlanner.winningPlan, "COUNT_SCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "COUNT_SCAN"));
explain = coll.explain().find({x: 0, $comment: "hi"}).count();
- assert(planHasStage(explain.queryPlanner.winningPlan, "COUNT_SCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "COUNT_SCAN"));
explain = coll.explain().find({x: 0}).hint({x: 1}).count();
- assert(planHasStage(explain.queryPlanner.winningPlan, "COUNT_SCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "COUNT_SCAN"));
explain = coll.explain().find({x: 0, $comment: "hi"}).hint({x: 1}).count();
- assert(planHasStage(explain.queryPlanner.winningPlan, "COUNT_SCAN"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "COUNT_SCAN"));
})();
diff --git a/jstests/core/regex6.js b/jstests/core/regex6.js
index b7e90664c4d..8872d1e4cca 100644
--- a/jstests/core/regex6.js
+++ b/jstests/core/regex6.js
@@ -1,4 +1,7 @@
// contributed by Andrew Kempe
+// This test makes assertions about how many keys are examined during query execution, which can
+// change depending on whether/how many documents are filtered out by the SHARDING_FILTER stage.
+// @tags: [assumes_unsharded_collection]
t = db.regex6;
t.drop();
diff --git a/jstests/core/return_key.js b/jstests/core/return_key.js
index b2442b43e6f..38843eaf0a3 100644
--- a/jstests/core/return_key.js
+++ b/jstests/core/return_key.js
@@ -32,9 +32,9 @@ load("jstests/libs/analyze_plan.js");
// Check that the plan is covered.
explain = coll.find().hint({a: 1}).sort({a: 1}).returnKey().explain();
- assert(isIndexOnly(explain.queryPlanner.winningPlan));
+ assert(isIndexOnly(db, explain.queryPlanner.winningPlan));
explain = coll.find().hint({a: 1}).sort({a: -1}).returnKey().explain();
- assert(isIndexOnly(explain.queryPlanner.winningPlan));
+ assert(isIndexOnly(db, explain.queryPlanner.winningPlan));
// returnKey with an in-memory sort.
results = coll.find().hint({a: 1}).sort({b: 1}).returnKey().toArray();
@@ -44,23 +44,23 @@ load("jstests/libs/analyze_plan.js");
// Check that the plan is not covered.
explain = coll.find().hint({a: 1}).sort({b: 1}).returnKey().explain();
- assert(!isIndexOnly(explain.queryPlanner.winningPlan));
+ assert(!isIndexOnly(db, explain.queryPlanner.winningPlan));
explain = coll.find().hint({a: 1}).sort({b: -1}).returnKey().explain();
- assert(!isIndexOnly(explain.queryPlanner.winningPlan));
+ assert(!isIndexOnly(db, explain.queryPlanner.winningPlan));
// returnKey takes precedence over other a regular inclusion projection. Should still be
// covered.
results = coll.find({}, {b: 1}).hint({a: 1}).sort({a: -1}).returnKey().toArray();
assert.eq(results, [{a: 3}, {a: 2}, {a: 1}]);
explain = coll.find({}, {b: 1}).hint({a: 1}).sort({a: -1}).returnKey().explain();
- assert(isIndexOnly(explain.queryPlanner.winningPlan));
+ assert(isIndexOnly(db, explain.queryPlanner.winningPlan));
// returnKey takes precedence over other a regular exclusion projection. Should still be
// covered.
results = coll.find({}, {a: 0}).hint({a: 1}).sort({a: -1}).returnKey().toArray();
assert.eq(results, [{a: 3}, {a: 2}, {a: 1}]);
explain = coll.find({}, {a: 0}).hint({a: 1}).sort({a: -1}).returnKey().explain();
- assert(isIndexOnly(explain.queryPlanner.winningPlan));
+ assert(isIndexOnly(db, explain.queryPlanner.winningPlan));
// Unlike other projections, sortKey meta-projection can co-exist with returnKey.
results =
diff --git a/jstests/core/set_type_change.js b/jstests/core/set_type_change.js
index ede59f7bcde..565da8be12e 100644
--- a/jstests/core/set_type_change.js
+++ b/jstests/core/set_type_change.js
@@ -7,9 +7,6 @@
* Tests that using the $set update modifier to change only the type of a field will actually update
* the document, including any relevant indices.
*/
-
-load("jstests/libs/analyze_plan.js"); // For 'isIndexOnly'.
-
(function() {
"use strict";
diff --git a/jstests/core/snapshot_queries.js b/jstests/core/snapshot_queries.js
index 33e50dc60fe..87364105d6d 100644
--- a/jstests/core/snapshot_queries.js
+++ b/jstests/core/snapshot_queries.js
@@ -1,4 +1,8 @@
-// @tags: [requires_getmore, requires_non_retryable_writes]
+// This test uses multiple batches to pause a cursors progress, so requires getMores. This test uses
+// a delete without a limit which is not retryable. It also makes assumptions about the order of
+// collection scans using the snapshot query option. This order can change when the collection is
+// sharded.
+// @tags: [requires_getmore, requires_non_retryable_writes, assumes_unsharded_collection]
// Regression test for edge cases in which .snapshot() queries could historically miss documents or
// return the same document twice.
diff --git a/jstests/core/sort_array.js b/jstests/core/sort_array.js
index bdec23fe4ea..1343d60972e 100644
--- a/jstests/core/sort_array.js
+++ b/jstests/core/sort_array.js
@@ -23,7 +23,7 @@
let cursor = coll.find(filter, project).sort(sort);
assert.eq(cursor.toArray(), expected);
let explain = coll.find(filter, project).sort(sort).explain();
- assert(planHasStage(explain.queryPlanner.winningPlan, "SORT"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "SORT"));
let pipeline = [
{$_internalInhibitOptimization: {}},
@@ -140,8 +140,8 @@
assert.commandWorked(coll.createIndex({a: 1, "b.c": 1}));
assert.writeOK(coll.insert({a: [1, 2, 3], b: {c: 9}}));
explain = coll.find({a: 2}).sort({"b.c": -1}).explain();
- assert(planHasStage(explain.queryPlanner.winningPlan, "IXSCAN"));
- assert(!planHasStage(explain.queryPlanner.winningPlan, "SORT"));
+ assert(planHasStage(db, explain.queryPlanner.winningPlan, "IXSCAN"));
+ assert(!planHasStage(db, explain.queryPlanner.winningPlan, "SORT"));
const pipeline = [
{$match: {a: 2}},
diff --git a/jstests/core/text_covered_matching.js b/jstests/core/text_covered_matching.js
index 0ac73bcbab6..3e9846e3895 100644
--- a/jstests/core/text_covered_matching.js
+++ b/jstests/core/text_covered_matching.js
@@ -32,7 +32,7 @@ load("jstests/libs/analyze_plan.js");
// - we return exactly one document.
let explainResult = coll.find({$text: {$search: "hello"}, b: 1}).explain("executionStats");
assert.commandWorked(explainResult);
- assert(planHasStage(explainResult.queryPlanner.winningPlan, "OR"));
+ assert(planHasStage(db, explainResult.queryPlanner.winningPlan, "OR"));
assert.eq(explainResult.executionStats.totalKeysExamined,
2,
"Unexpected number of keys examined: " + tojson(explainResult));
@@ -49,7 +49,7 @@ load("jstests/libs/analyze_plan.js");
{a: 1, b: 1, c: 1, textScore: {$meta: "textScore"}})
.explain("executionStats");
assert.commandWorked(explainResult);
- assert(planHasStage(explainResult.queryPlanner.winningPlan, "TEXT_OR"));
+ assert(planHasStage(db, explainResult.queryPlanner.winningPlan, "TEXT_OR"));
assert.eq(explainResult.executionStats.totalKeysExamined,
2,
"Unexpected number of keys examined: " + tojson(explainResult));
@@ -72,7 +72,7 @@ load("jstests/libs/analyze_plan.js");
// - we return exactly one document.
explainResult = coll.find({$text: {$search: "hello"}, c: 1}).explain("executionStats");
assert.commandWorked(explainResult);
- assert(planHasStage(explainResult.queryPlanner.winningPlan, "OR"));
+ assert(planHasStage(db, explainResult.queryPlanner.winningPlan, "OR"));
assert.eq(explainResult.executionStats.totalKeysExamined,
2,
"Unexpected number of keys examined: " + tojson(explainResult));
@@ -117,7 +117,7 @@ load("jstests/libs/analyze_plan.js");
// - we return exactly one document.
explainResult = coll.find({$text: {$search: "hello"}, "b.d": 1}).explain("executionStats");
assert.commandWorked(explainResult);
- assert(planHasStage(explainResult.queryPlanner.winningPlan, "OR"));
+ assert(planHasStage(db, explainResult.queryPlanner.winningPlan, "OR"));
assert.eq(explainResult.executionStats.totalKeysExamined,
2,
"Unexpected number of keys examined: " + tojson(explainResult));
@@ -134,7 +134,7 @@ load("jstests/libs/analyze_plan.js");
{a: 1, b: 1, c: 1, textScore: {$meta: "textScore"}})
.explain("executionStats");
assert.commandWorked(explainResult);
- assert(planHasStage(explainResult.queryPlanner.winningPlan, "TEXT_OR"));
+ assert(planHasStage(db, explainResult.queryPlanner.winningPlan, "TEXT_OR"));
assert.eq(explainResult.executionStats.totalKeysExamined,
2,
"Unexpected number of keys examined: " + tojson(explainResult));
@@ -157,7 +157,7 @@ load("jstests/libs/analyze_plan.js");
// - we return exactly one document.
explainResult = coll.find({$text: {$search: "hello"}, "c.e": 1}).explain("executionStats");
assert.commandWorked(explainResult);
- assert(planHasStage(explainResult.queryPlanner.winningPlan, "OR"));
+ assert(planHasStage(db, explainResult.queryPlanner.winningPlan, "OR"));
assert.eq(explainResult.executionStats.totalKeysExamined,
2,
"Unexpected number of keys examined: " + tojson(explainResult));
diff --git a/jstests/core/ts1.js b/jstests/core/ts1.js
index 342ff3215d7..79a2db95dca 100644
--- a/jstests/core/ts1.js
+++ b/jstests/core/ts1.js
@@ -1,37 +1,45 @@
-t = db.ts1;
-t.drop();
-
-N = 20;
-
-for (i = 0; i < N; i++) {
- t.insert({_id: i, x: new Timestamp()});
- sleep(100);
-}
-
-function get(i) {
- return t.findOne({_id: i}).x;
-}
-
-function cmp(a, b) {
- if (a.t < b.t)
- return -1;
- if (a.t > b.t)
- return 1;
-
- return a.i - b.i;
-}
-
-for (i = 0; i < N - 1; i++) {
- a = get(i);
- b = get(i + 1);
- // print( tojson(a) + "\t" + tojson(b) + "\t" + cmp(a,b) );
- assert.gt(0, cmp(a, b), "cmp " + i);
-}
-
-assert.eq(N, t.find({x: {$type: 17}}).itcount(), "B1");
-assert.eq(0, t.find({x: {$type: 3}}).itcount(), "B2");
-
-t.insert({_id: 100, x: new Timestamp(123456, 50)});
-x = t.findOne({_id: 100}).x;
-assert.eq(123456, x.t, "C1");
-assert.eq(50, x.i, "C2");
+// Tests that timestamps are inserted in increasing order. This test assumes that timestamps
+// inserted within the same second will have increasing increment values, which may not be the case
+// if the inserts are into a sharded collection.
+// @tags: [assumes_unsharded_collection]
+(function() {
+ "use strict";
+ const t = db.ts1;
+ t.drop();
+
+ const N = 20;
+
+ for (let i = 0; i < N; i++) {
+ assert.writeOK(t.insert({_id: i, x: new Timestamp()}));
+ sleep(100);
+ }
+
+ function get(i) {
+ return t.findOne({_id: i}).x;
+ }
+
+ function cmp(a, b) {
+ if (a.t < b.t)
+ return -1;
+ if (a.t > b.t)
+ return 1;
+
+ return a.i - b.i;
+ }
+
+ for (let i = 0; i < N - 1; i++) {
+ const a = get(i);
+ const b = get(i + 1);
+ assert.gt(0,
+ cmp(a, b),
+ `Expected ${tojson(a)} to be smaller than ${tojson(b)} (at iteration ${i})`);
+ }
+
+ assert.eq(N, t.find({x: {$type: 17}}).itcount());
+ assert.eq(0, t.find({x: {$type: 3}}).itcount());
+
+ assert.writeOK(t.insert({_id: 100, x: new Timestamp(123456, 50)}));
+ const x = t.findOne({_id: 100}).x;
+ assert.eq(123456, x.t);
+ assert.eq(50, x.i);
+}());
diff --git a/jstests/core/updatej.js b/jstests/core/updatej.js
index 2c4f6246f11..b96233f448d 100644
--- a/jstests/core/updatej.js
+++ b/jstests/core/updatej.js
@@ -1,7 +1,9 @@
-// @tags: [requires_non_retryable_writes]
-
// Test that update validation failure terminates the update without modifying subsequent
// documents. SERVER-4779
+// This test uses a multi-update, which is not retryable. The behavior it is testing is also not
+// true of sharded clusters, since one shard may continue applying updates while the other
+// encounters an error.
+// @tags: [requires_non_retryable_writes, assumes_unsharded_collection]
t = db.jstests_updatej;
t.drop();
@@ -10,5 +12,5 @@ t.save({a: []});
t.save({a: 1});
t.save({a: []});
-t.update({}, {$push: {a: 2}}, false, true);
+assert.writeError(t.update({}, {$push: {a: 2}}, false, true));
assert.eq(1, t.count({a: 2}));
diff --git a/jstests/core/where4.js b/jstests/core/where4.js
index df2f01a498e..974748f8dbc 100644
--- a/jstests/core/where4.js
+++ b/jstests/core/where4.js
@@ -1,4 +1,6 @@
-// @tags: [requires_non_retryable_writes]
+// This test expects a function stored in the system.js collection to be available for a map/reduce,
+// which may not be the case if it is implicitly sharded in a passthrough.
+// @tags: [requires_non_retryable_writes, assumes_unsharded_collection]
var myDB = db.getSiblingDB("where4");
@@ -31,4 +33,4 @@ assert.writeOK(
myDB.where4.update({$where: "where4_addOne(this.x) == 2"}, {$inc: {y: 1}}, false, true));
assert.eq(3, myDB.where4.findOne({x: 1}).y);
-assert.eq(1, myDB.where4.findOne({x: 2}).y); \ No newline at end of file
+assert.eq(1, myDB.where4.findOne({x: 2}).y);