summaryrefslogtreecommitdiff
path: root/jstests/core/wildcard_index_projection.js
blob: a7fde8e57d8844e5e21cde2f29e1345bc6033d0f (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
/**
 * Tests that a wildcard index with an exclusion projection but including _id field gets saved
 * properly. Exercises the fix for SERVER-52814.
 * @tags: [
 *   assumes_read_concern_local,
 *   no_selinux,
 * ]
 */

(function() {
"use strict";

load("jstests/libs/fixture_helpers.js");  // For isMongos.
load("jstests/libs/analyze_plan.js");     // For getRejectedPlan helper to analyze explain() output.

const collName = jsTestName();
const coll = db[collName];
coll.drop();
coll.createIndex({"$**": 1}, {wildcardProjection: {name: 0, type: 0, _id: 1}});

const sharded = FixtureHelpers.isMongos(db);

// Return the explain object containing the winning plan and rejected plans.
function getExplainObj(explainRes) {
    if (sharded) {
        return explainRes.queryPlanner.winningPlan.shards[0];
    }

    return explainRes.queryPlanner;
}

const indexes = coll.getIndexes().filter(idx => idx.name === "$**_1");
assert.eq(1, indexes.length);
const indexSpec = indexes[0];
assert.eq(false, indexSpec.wildcardProjection.name, indexes);
assert.eq(false, indexSpec.wildcardProjection.type, indexes);
assert.eq(true, indexSpec.wildcardProjection._id, indexes);

coll.insert({name: "Ted", type: "Person", _id: 1});
coll.insert({name: "Bernard", type: "Person", _id: 2});
const explainResFull = coll.find({_id: {$eq: 1}}).explain();
const plannerRes = getExplainObj(explainResFull);
// For a query on _id we expect that the IDHACK plan will be selected. However, we should also
// observe a rejected plan which uses the wildcard index to resolve _id. In a sharded cluster we
// may also need to skip the _id: hashed index.
let indexStage = getRejectedPlan(plannerRes.rejectedPlans[0]).inputStage;
if (sharded) {
    if (indexStage.keyPattern._id === "hashed") {
        assert.eq(plannerRes.rejectedPlans.length, 2, plannerRes.rejectedPlans);
        indexStage = getRejectedPlan(plannerRes.rejectedPlans[1]).inputStage;
    }
} else {
    assert.eq(plannerRes.rejectedPlans.length, 1, plannerRes.rejectedPlans);
}

assert.eq(indexStage.stage, "IXSCAN", indexStage);
assert.eq(indexStage.keyPattern, {"$_path": 1, "_id": 1}, indexStage);

// Ensure we use the index for _id if we supply a hint.
const hintExplainRes = coll.find({_id: {$eq: 1}}).hint("$**_1").explain();
const winningPlan = getWinningPlan(getExplainObj(hintExplainRes));
assert.eq(winningPlan.inputStage.stage, "IXSCAN", winningPlan.inputStage);
assert.eq(winningPlan.inputStage.keyPattern, {$_path: 1, _id: 1}, winningPlan.inputStage);

// Test that the results are correct.
const hintedResults = coll.find({_id: {$eq: 1}}).hint("$**_1").toArray();
assert.eq(hintedResults.length, 1, hintedResults);
assert.eq(hintedResults[0]._id, 1, hintedResults);
})();