diff options
| author | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-14 14:26:38 -0300 |
|---|---|---|
| committer | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-14 14:26:38 -0300 |
| commit | 294bc6ecabf14c09c9bc8644704921dcf97cb44e (patch) | |
| tree | 279b1e0bab53901a1647ac63c1c724f0f789a663 /jstests/core/elemmatch_index.js | |
| parent | 70be7c27a251621187a1de533462ae2bb1e3bd39 (diff) | |
| parent | 1e917fd798aa25b7066d4b414b51184f13d5a092 (diff) | |
Update upstream source from tag 'upstream/6.0.10'debian/6.0.10-1
Update to upstream version '6.0.10'
with Debian dir 2d176fa254eee97b139f712fec5709641335a8c3
Diffstat (limited to 'jstests/core/elemmatch_index.js')
| -rw-r--r-- | jstests/core/elemmatch_index.js | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/jstests/core/elemmatch_index.js b/jstests/core/elemmatch_index.js new file mode 100644 index 00000000000..a1941620a48 --- /dev/null +++ b/jstests/core/elemmatch_index.js @@ -0,0 +1,115 @@ +/** + * Test that queries containing $elemMatch correctly use an index if each child expression is + * compatible with the index. + * @tags: [ + * assumes_balancer_off, + * assumes_read_concern_local, + * ] + */ +(function() { +"use strict"; + +load("jstests/libs/analyze_plan.js"); + +const coll = db.elemMatch_index; +coll.drop(); + +assert.commandWorked(coll.insert({a: 1})); +assert.commandWorked(coll.insert({a: [{}]})); +assert.commandWorked(coll.insert({a: [1, null]})); +assert.commandWorked(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(db, getWinningPlan(explainPlan.queryPlanner)), 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); + +(function() { +assert(coll.drop()); +assert.commandWorked(coll.insert({a: [{b: {c: "x"}}]})); +assert.commandWorked(coll.createIndex({"a.b.c": 1})); + +// Tests $elemMatch with path components that are empty strings. The system should not attempt to +// use the index for these queries. +assertIndexResults(coll, {"": {$elemMatch: {"a.b.c": "x"}}}, false, 0); +assertIndexResults(coll, {"": {$all: [{$elemMatch: {"a.b.c": "x"}}]}}, false, 0); +assertIndexResults(coll, {a: {$elemMatch: {"": {$elemMatch: {"b.c": "x"}}}}}, false, 0); + +// Tests $elemMatch with supporting index and no path components that are empty strings. +assertIndexResults(coll, {a: {$elemMatch: {"b.c": "x"}}}, true, 1); +assertIndexResults(coll, {a: {$all: [{$elemMatch: {"b.c": "x"}}]}}, true, 1); +})(); + +(function() { +const coll = db.index_elemmatch1; +coll.drop(); + +let x = 0; +let y = 0; +const bulk = coll.initializeUnorderedBulkOp(); +for (let a = 0; a < 10; a++) { + for (let b = 0; b < 10; b++) { + bulk.insert({a: a, b: b % 10, arr: [{x: x++ % 10, y: y++ % 10}]}); + } +} +assert.commandWorked(bulk.execute()); + +assert.commandWorked(coll.createIndex({a: 1, b: 1})); +assert.commandWorked(coll.createIndex({"arr.x": 1, a: 1})); + +const query = { + a: 5, + b: {$in: [1, 3, 5]}, + arr: {$elemMatch: {x: 5, y: 5}} +}; + +const count = coll.find(query).itcount(); +assert.eq(count, 1); + +const explain = coll.find(query).hint({"arr.x": 1, a: 1}).explain("executionStats"); +assert.commandWorked(explain); +assert.eq(count, explain.executionStats.totalKeysExamined, explain); +})(); +})(); |
