summaryrefslogtreecommitdiff
path: root/jstests/core/index_elemmatch2.js
diff options
context:
space:
mode:
Diffstat (limited to 'jstests/core/index_elemmatch2.js')
-rw-r--r--jstests/core/index_elemmatch2.js63
1 files changed, 63 insertions, 0 deletions
diff --git a/jstests/core/index_elemmatch2.js b/jstests/core/index_elemmatch2.js
new file mode 100644
index 00000000000..ecd24035284
--- /dev/null
+++ b/jstests/core/index_elemmatch2.js
@@ -0,0 +1,63 @@
+/**
+ * Test that queries containing $elemMatch correctly use an index if each child expression is
+ * compatible with the index.
+ */
+(function() {
+ "use strict";
+
+ load("jstests/libs/analyze_plan.js");
+
+ const coll = db.elemMatch_index;
+ coll.drop();
+
+ assert.writeOK(coll.insert({a: 1}));
+ assert.writeOK(coll.insert({a: [{}]}));
+ assert.writeOK(coll.insert({a: [1, null]}));
+ assert.writeOK(coll.insert({a: [{type: "Point", coordinates: [0, 0]}]}));
+
+ assert.commandWorked(coll.createIndex({a: 1}, {sparse: true}));
+
+ function assertIndexResults(coll, query, useIndex, nReturned) {
+ const explainPlan = coll.find(query).explain("executionStats");
+ assert.eq(isIxscan(explainPlan.queryPlanner.winningPlan), useIndex);
+ assert.eq(explainPlan.executionStats.nReturned, nReturned);
+ }
+
+ assertIndexResults(coll, {a: {$elemMatch: {$exists: false}}}, false, 0);
+
+ // An $elemMatch predicate is treated as nested, and the index should be used for $exists:true.
+ assertIndexResults(coll, {a: {$elemMatch: {$exists: true}}}, true, 3);
+
+ // $not within $elemMatch should not attempt to use a sparse index for $exists:false.
+ assertIndexResults(coll, {a: {$elemMatch: {$not: {$exists: false}}}}, false, 3);
+ assertIndexResults(coll, {a: {$elemMatch: {$gt: 0, $not: {$exists: false}}}}, false, 1);
+
+ // $geo within $elemMatch should not attempt to use a non-geo index.
+ assertIndexResults(
+ coll,
+ {
+ a: {
+ $elemMatch: {
+ $geoWithin: {
+ $geometry:
+ {type: "Polygon", coordinates: [[[0, 0], [0, 1], [1, 0], [0, 0]]]}
+ }
+ }
+ }
+ },
+ false,
+ 1);
+
+ // $in with a null value within $elemMatch should use a sparse index.
+ assertIndexResults(coll, {a: {$elemMatch: {$in: [null]}}}, true, 1);
+
+ // $eq with a null value within $elemMatch should use a sparse index.
+ assertIndexResults(coll, {a: {$elemMatch: {$eq: null}}}, true, 1);
+
+ // A negated regex within $elemMatch should not use an index, sparse or not.
+ assertIndexResults(coll, {a: {$elemMatch: {$not: {$in: [/^a/]}}}}, false, 3);
+
+ coll.dropIndexes();
+ assert.commandWorked(coll.createIndex({a: 1}));
+ assertIndexResults(coll, {a: {$elemMatch: {$not: {$in: [/^a/]}}}}, false, 3);
+})();