summaryrefslogtreecommitdiff
path: root/jstests/core/explain_multikey.js
blob: 9bea359edb44a6131795c0a0ca165635991966db (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
// Tests the output of the multikey information in the explain output.
//
// This test examines the explain output to verify that certain indexes are multi-key, which may not
// be the case on all shards.
// @tags: [
//   assumes_unsharded_collection,
// ]
(function() {
"use strict";

load("jstests/libs/analyze_plan.js");

const coll = db.explain_multikey;
const keyPattern = {
    a: 1,
    "b.c": 1,
    "b.d": 1,
};

/**
 * Creates an index with a key pattern of 'keyPattern' on a collection containing a single
 * document and runs the specified command under explain.
 *
 * @param {Object} testOptions
 * @param {Object} testOptions.docToInsert - The document to insert into the collection.
 * @param {Object} testOptions.commandObj - The operation to run "explain" on.
 * @param {string} testOptions.stage - The plan summary name of the winning plan.
 *
 * @returns {Object} The "queryPlanner" information of the stage with the specified plan summary
 * name.
 */
function createIndexAndRunExplain(testOptions) {
    coll.drop();

    assert.commandWorked(coll.createIndex(keyPattern));
    assert.commandWorked(coll.insert(testOptions.docToInsert));

    const explain = db.runCommand({explain: testOptions.commandObj});
    assert.commandWorked(explain);
    const winningPlan = getWinningPlan(explain.queryPlanner);

    assert(planHasStage(db, winningPlan, testOptions.stage),
           "expected stage to be present: " + tojson(explain));
    return getPlanStage(winningPlan, testOptions.stage);
}

// Calls createIndexAndRunExplain() twice: once with a document that causes the created index to
// be multikey, and again with a document that doesn't cause the created index to be multikey.
function verifyMultikeyInfoInExplainOutput(testOptions) {
    // Insert a document that should cause the index to be multikey.
    testOptions.docToInsert = {
        a: 1,
        b: [{c: ["w", "x"], d: 3}, {c: ["y", "z"], d: 4}],
    };
    let stage = createIndexAndRunExplain(testOptions);

    assert.eq(true, stage.isMultiKey, "expected index to be multikey: " + tojson(stage));
    assert.eq({a: [], "b.c": ["b", "b.c"], "b.d": ["b"]}, stage.multiKeyPaths, tojson(stage));

    // Drop the collection and insert a document that shouldn't cause the index to be multikey.
    testOptions.docToInsert = {
        a: 1,
        b: {c: "w", d: 4},
    };
    stage = createIndexAndRunExplain(testOptions);

    assert.eq(false, stage.isMultiKey, "expected index not to be multikey: " + tojson(stage));
    assert.eq({a: [], "b.c": [], "b.d": []}, stage.multiKeyPaths, tojson(stage));
}

verifyMultikeyInfoInExplainOutput({
    commandObj: {find: coll.getName(), hint: keyPattern},
    stage: "IXSCAN",
});

verifyMultikeyInfoInExplainOutput({
    commandObj: {count: coll.getName(), hint: keyPattern},
    stage: "COUNT_SCAN",
});

verifyMultikeyInfoInExplainOutput({
    commandObj: {distinct: coll.getName(), key: "a"},
    stage: "DISTINCT_SCAN",
});
})();