summaryrefslogtreecommitdiff
path: root/jstests/core/elemmatch_or_pushdown.js
blob: 2edef4d0678afb00bc5df9667afcd5ad6d801487 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
/**
 * Tests that an $elemMatch-$or query is evaluated correctly. Designed to reproduce SERVER-33005 and
 * SERVER-38164.
 */
(function() {
"use strict";

const coll = db.elemmatch_or_pushdown;
coll.drop();

assert.commandWorked(coll.insert({_id: 0, a: 1, b: [{c: 4}]}));
assert.commandWorked(coll.insert({_id: 1, a: 2, b: [{c: 4}]}));
assert.commandWorked(coll.insert({_id: 2, a: 2, b: [{c: 5}]}));
assert.commandWorked(coll.insert({_id: 3, a: 1, b: [{c: 5}]}));
assert.commandWorked(coll.insert({_id: 4, a: 1, b: [{c: 6}]}));
assert.commandWorked(coll.insert({_id: 5, a: 1, b: [{c: 7}]}));
assert.commandWorked(coll.createIndex({a: 1, "b.c": 1}));

assert.eq(coll.find({a: 1, b: {$elemMatch: {$or: [{c: 4}, {c: 5}]}}}).sort({_id: 1}).toArray(),
          [{_id: 0, a: 1, b: [{c: 4}]}, {_id: 3, a: 1, b: [{c: 5}]}]);
assert.eq(coll.find({a: 1, $or: [{a: 2}, {b: {$elemMatch: {$or: [{c: 4}, {c: 5}]}}}]})
              .sort({_id: 1})
              .toArray(),
          [{_id: 0, a: 1, b: [{c: 4}]}, {_id: 3, a: 1, b: [{c: 5}]}]);

coll.drop();
assert.commandWorked(coll.insert({_id: 0, a: 5, b: [{c: [{f: 8}], d: 6}]}));
assert.commandWorked(coll.insert({_id: 1, a: 4, b: [{c: [{f: 8}], d: 6}]}));
assert.commandWorked(coll.insert({_id: 2, a: 5, b: [{c: [{f: 8}], d: 7}]}));
assert.commandWorked(coll.insert({_id: 3, a: 4, b: [{c: [{f: 9}], d: 6}]}));
assert.commandWorked(coll.insert({_id: 4, a: 5, b: [{c: [{f: 8}], e: 7}]}));
assert.commandWorked(coll.insert({_id: 5, a: 4, b: [{c: [{f: 8}], e: 7}]}));
assert.commandWorked(coll.insert({_id: 6, a: 5, b: [{c: [{f: 8}], e: 8}]}));
assert.commandWorked(coll.insert({_id: 7, a: 5, b: [{c: [{f: 9}], e: 7}]}));
assert.commandWorked(coll.createIndex({"b.d": 1, "b.c.f": 1}));
assert.commandWorked(coll.createIndex({"b.e": 1, "b.c.f": 1}));

assert.eq(coll.find({a: 5, b: {$elemMatch: {c: {$elemMatch: {f: 8}}, $or: [{d: 6}, {e: 7}]}}})
              .sort({_id: 1})
              .toArray(),
          [{_id: 0, a: 5, b: [{c: [{f: 8}], d: 6}]}, {_id: 4, a: 5, b: [{c: [{f: 8}], e: 7}]}]);

// Test that $not predicates in $elemMatch can be pushed into an $or sibling of the $elemMatch.
coll.drop();
assert.commandWorked(coll.insert({_id: 0, arr: [{a: 0, b: 2}], c: 4, d: 5}));
assert.commandWorked(coll.insert({_id: 1, arr: [{a: 1, b: 2}], c: 4, d: 5}));
assert.commandWorked(coll.insert({_id: 2, arr: [{a: 0, b: 3}], c: 4, d: 5}));
assert.commandWorked(coll.insert({_id: 3, arr: [{a: 1, b: 3}], c: 4, d: 5}));
assert.commandWorked(coll.insert({_id: 4, arr: [{a: 0, b: 2}], c: 6, d: 7}));
assert.commandWorked(coll.insert({_id: 5, arr: [{a: 1, b: 2}], c: 6, d: 7}));
assert.commandWorked(coll.insert({_id: 6, arr: [{a: 0, b: 3}], c: 6, d: 7}));
assert.commandWorked(coll.insert({_id: 7, arr: [{a: 1, b: 3}], c: 6, d: 7}));

const keyPattern = {
    "arr.a": 1,
    "arr.b": 1,
    c: 1,
    d: 1
};
assert.commandWorked(coll.createIndex(keyPattern));

const elemMatchOr = {
    arr: {$elemMatch: {a: {$ne: 1}, $or: [{b: 2}, {b: 3}]}},
    $or: [
        {c: 4, d: 5},
        {c: 6, d: 7},
    ],
};

// Confirm that we get the same results using the index and a COLLSCAN.
for (let hint of [keyPattern, {$natural: 1}]) {
    assert.eq(coll.find(elemMatchOr, {_id: 1}).sort({_id: 1}).hint(hint).toArray(),
              [{_id: 0}, {_id: 2}, {_id: 4}, {_id: 6}]);

    assert.eq(
        coll.aggregate(
                [
                    {$match: {arr: {$elemMatch: {a: {$ne: 1}}}, $or: [{c: 4, d: 5}, {c: 6, d: 7}]}},
                    {$project: {_id: 1}},
                    {$sort: {_id: 1}}
                ],
                {hint: hint})
            .toArray(),
        [{_id: 0}, {_id: 2}, {_id: 4}, {_id: 6}]);
}
}());