summaryrefslogtreecommitdiff
path: root/jstests/query_golden/not_pushdown.js
blob: dc61175e001f213822eff3fe9082ec907a0aa1f3 (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
/**
 * Test query predicates with combinations of $not and array traversal.
 * When possible, we should remove Traverse nodes.
 *
 * @tags: [
 *   # Checks explain.
 *   requires_cqf,
 * ]
 */
(function() {
"use strict";

load("jstests/libs/optimizer_utils.js");  // For leftmostLeafStage

const coll = db.cqf_not_pushdown;
coll.drop();
assert.commandWorked(coll.createIndex({'one.one.one.one': 1}));
assert.commandWorked(coll.createIndex({'one.one.one.many': 1}));
assert.commandWorked(coll.createIndex({'many.one.one.one': 1}));
assert.commandWorked(coll.createIndex({'many.one.one.many': 1}));
assert.commandWorked(coll.createIndex({'many.many.many.many': 1}));
let i = 0;
assert.commandWorked(coll.insert([
    {_id: ++i, one: {one: {one: {one: 2}}}},
    {_id: ++i, one: {one: {one: {many: [1, 2, 3]}}}},
    {
        _id: ++i,
        many: [
            {one: {one: {one: 1}}},
            {one: {one: {one: 2}}},
            {one: {one: {one: 3}}},
        ]
    },
    {
        _id: ++i,
        many: [
            {one: {one: {many: [1, 2, 3]}}},
            {one: {one: {many: [4, 5]}}},
        ],
    },
    {_id: ++i, many: [{many: [{many: [{many: [1, 2, 3]}]}]}]},
]));
// Generate enough documents for index to be preferable.
assert.commandWorked(coll.insert(Array.from({length: 100}, (_, i) => ({_id: i + 1000}))));

function run(note, pipeline) {
    jsTestLog(`Query: ${tojsononeline(pipeline)}\nnote: ${note}`);

    print(`Operators used: `);
    const explain = coll.explain().aggregate(pipeline);
    const ops =
        findSubtrees(explain, node => node.op === 'Not' || node.op === 'Eq' || node.op === 'Neq')
            .map(node => node.op);
    printjson(ops);
}

// Simple case: non-multikey.
run('Should be optimized to Neq', [{$match: {'one.one.one.one': {$ne: 7}}}]);

// Multikey case: we have Traverse in between Not and Eq, which is not the same as Neq.
run('Should stay as Not Traverse Eq', [{$match: {'one.one.one.many': {$ne: 7}}}]);
run('Should stay as Not Traverse Eq', [{$match: {'many.one.one.one': {$ne: 7}}}]);
run('Should stay as Not Traverse Eq', [{$match: {'many.one.one.many': {$ne: 7}}}]);
run('Should stay as Not Traverse Eq', [{$match: {'many.many.many.many': {$ne: 7}}}]);

// We have an $elemMatch (multikey), but no Traverse underneath the Not.
run('Should be optimized to Neq', [{$match: {'many': {$elemMatch: {'one.one.one': {$ne: 7}}}}}]);
run('Should be optimized to Neq', [{$match: {'many.one': {$elemMatch: {'one.one': {$ne: 7}}}}}]);
})();