summaryrefslogtreecommitdiff
path: root/jstests/core/index/wildcard/wildcard_index_nonblocking_sort.js
diff options
context:
space:
mode:
Diffstat (limited to 'jstests/core/index/wildcard/wildcard_index_nonblocking_sort.js')
-rw-r--r--jstests/core/index/wildcard/wildcard_index_nonblocking_sort.js87
1 files changed, 87 insertions, 0 deletions
diff --git a/jstests/core/index/wildcard/wildcard_index_nonblocking_sort.js b/jstests/core/index/wildcard/wildcard_index_nonblocking_sort.js
new file mode 100644
index 00000000000..c0cada14004
--- /dev/null
+++ b/jstests/core/index/wildcard/wildcard_index_nonblocking_sort.js
@@ -0,0 +1,87 @@
+// @tags: [
+// assumes_balancer_off,
+// assumes_read_concern_local,
+// ]
+(function() {
+"use strict";
+
+load("jstests/aggregation/extras/utils.js"); // For arrayEq().
+load("jstests/libs/analyze_plan.js"); // For getPlanStages().
+load("jstests/libs/fixture_helpers.js"); // For numberOfShardsForCollection().
+
+const coll = db.wildcard_nonblocking_sort;
+coll.drop();
+
+assert.commandWorked(coll.createIndex({"$**": 1}, {wildcardProjection: {"excludedField": 0}}));
+
+for (let i = 0; i < 50; i++) {
+ assert.commandWorked(coll.insert({a: i, b: -i, x: [123], excludedField: i}));
+}
+
+function checkQueryHasSameResultsWhenUsingIdIndex(query, sort, projection) {
+ const l = coll.find(query, projection).sort(sort).toArray();
+ const r = coll.find(query, projection).sort(sort).hint({$natural: 1}).toArray();
+ assert(arrayEq(l, r));
+}
+
+function checkQueryUsesSortType(query, sort, projection, isBlocking) {
+ const explain = assert.commandWorked(coll.find(query, projection).sort(sort).explain());
+ const plan = getWinningPlan(explain.queryPlanner);
+
+ const ixScans = getPlanStages(plan, "IXSCAN");
+ const sorts = getPlanStages(plan, "SORT");
+
+ if (isBlocking) {
+ assert.eq(sorts.length, FixtureHelpers.numberOfShardsForCollection(coll), explain);
+ assert.eq(sorts[0].sortPattern, sort, explain);
+
+ // A blocking sort may or may not use the index, so we don't check the length of
+ // 'ixScans'.
+ } else {
+ assert.eq(sorts.length, 0, explain);
+ assert.eq(ixScans.length, FixtureHelpers.numberOfShardsForCollection(coll), explain);
+
+ const sortKey = Object.keys(sort)[0];
+ assert.docEq({$_path: 1, [sortKey]: 1}, ixScans[0].keyPattern);
+ }
+}
+
+function checkQueryUsesNonBlockingSortAndGetsCorrectResults(query, sort, projection) {
+ checkQueryUsesSortType(query, sort, projection, false);
+ checkQueryHasSameResultsWhenUsingIdIndex(query, sort, projection);
+}
+
+function checkQueryUsesBlockingSortAndGetsCorrectResults(query, sort, projection) {
+ checkQueryUsesSortType(query, sort, projection, true);
+ checkQueryHasSameResultsWhenUsingIdIndex(query, sort, projection);
+}
+
+function runSortTests(dir, proj) {
+ // Test that the $** index can provide a non-blocking sort where appropriate.
+ checkQueryUsesNonBlockingSortAndGetsCorrectResults({a: {$gte: 0}}, {a: dir}, proj);
+ checkQueryUsesNonBlockingSortAndGetsCorrectResults({a: {$gte: 0}, x: 123}, {a: dir}, proj);
+
+ // Test that the $** index can produce a solution with a blocking sort where appropriate.
+ checkQueryUsesBlockingSortAndGetsCorrectResults({a: {$gte: 0}}, {a: dir, b: dir}, proj);
+ checkQueryUsesBlockingSortAndGetsCorrectResults({a: {$gte: 0}}, {a: dir, b: -dir}, proj);
+ checkQueryUsesBlockingSortAndGetsCorrectResults({a: {$gte: 0}}, {a: -dir, b: dir}, proj);
+ checkQueryUsesBlockingSortAndGetsCorrectResults({a: {$exists: true}}, {a: dir}, proj);
+ checkQueryUsesBlockingSortAndGetsCorrectResults({}, {a: dir}, proj);
+
+ // Test sorted queries on a field that is excluded by the $** index's wildcardProjection.
+ checkQueryUsesBlockingSortAndGetsCorrectResults(
+ {excludedField: {$gte: 0}}, {excludedField: dir}, proj);
+
+ // Test sorted queries on a multikey field, with and without $elemMatch.
+ checkQueryUsesBlockingSortAndGetsCorrectResults({x: 123}, {a: dir}, proj);
+ checkQueryUsesBlockingSortAndGetsCorrectResults({x: {$elemMatch: {$eq: 123}}}, {x: dir}, proj);
+ checkQueryUsesBlockingSortAndGetsCorrectResults({x: {$elemMatch: {$eq: 123}}}, {a: dir}, proj);
+}
+
+// Run each test for both ascending and descending sorts, with and without a projection.
+for (let dir of [1, -1]) {
+ for (let proj of [{}, {_id: 0, a: 1}]) {
+ runSortTests(dir, proj);
+ }
+}
+})();