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);
})();
|