summaryrefslogtreecommitdiff
path: root/jstests/core/explain_distinct.js
blob: 1c4d6612acb4e9f8aa564ad01447c0ab5a894a15 (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
87
88
89
90
91
// Cannot implicitly shard accessed collections because of collection existing when none
// expected.
// @tags: [assumes_no_implicit_collection_creation_after_drop]

/**
 * This test ensures that explain on the distinct command works.
 */
(function() {
'use strict';

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

var collName = "jstests_explain_distinct";
var coll = db[collName];

function runDistinctExplain(collection, keyString, query) {
    var distinctCmd = {distinct: collection.getName(), key: keyString};

    if (typeof query !== 'undefined') {
        distinctCmd.query = query;
    }

    return coll.runCommand({explain: distinctCmd, verbosity: 'executionStats'});
}

coll.drop();

// Collection doesn't exist.
var explain = runDistinctExplain(coll, 'a', {});
assert.commandWorked(explain);
assert(planHasStage(db, explain.queryPlanner.winningPlan, "EOF"));

// Insert the data to perform distinct() on.
for (var i = 0; i < 10; i++) {
    assert.writeOK(coll.insert({a: 1, b: 1}));
    assert.writeOK(coll.insert({a: 2, c: 1}));
}

assert.commandFailed(runDistinctExplain(coll, {}, {}));            // Bad keyString.
assert.commandFailed(runDistinctExplain(coll, 'a', 'a'));          // Bad query.
assert.commandFailed(runDistinctExplain(coll, 'b', {$not: 1}));    // Bad query.
assert.commandFailed(runDistinctExplain(coll, 'a', {$not: 1}));    // Bad query.
assert.commandFailed(runDistinctExplain(coll, '_id', {$not: 1}));  // Bad query.

// Ensure that server accepts a distinct command with no 'query' field.
assert.commandWorked(runDistinctExplain(coll, '', null));
assert.commandWorked(runDistinctExplain(coll, ''));

assert.eq([1], coll.distinct('b'));
var explain = runDistinctExplain(coll, 'b', {});
assert.commandWorked(explain);
assert.eq(20, explain.executionStats.nReturned);
assert(isCollscan(db, explain.queryPlanner.winningPlan));

assert.commandWorked(coll.createIndex({a: 1}));

assert.eq([1, 2], coll.distinct('a'));
var explain = runDistinctExplain(coll, 'a', {});
assert.commandWorked(explain);
assert.eq(2, explain.executionStats.nReturned);
assert(planHasStage(db, explain.queryPlanner.winningPlan, "PROJECTION_COVERED"));
assert(planHasStage(db, explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));

// Check that the DISTINCT_SCAN stage has the correct stats.
var stage = getPlanStage(explain.queryPlanner.winningPlan, "DISTINCT_SCAN");
assert.eq({a: 1}, stage.keyPattern);
assert.eq("a_1", stage.indexName);
assert.eq(false, stage.isMultiKey);
assert.eq(false, stage.isUnique);
assert.eq(false, stage.isSparse);
assert.eq(false, stage.isPartial);
assert.lte(1, stage.indexVersion);
assert("indexBounds" in stage);

assert.commandWorked(coll.createIndex({a: 1, b: 1}));

assert.eq([1], coll.distinct('a', {a: 1}));
var explain = runDistinctExplain(coll, 'a', {a: 1});
assert.commandWorked(explain);
assert.eq(1, explain.executionStats.nReturned);
assert(planHasStage(db, explain.queryPlanner.winningPlan, "PROJECTION_COVERED"));
assert(planHasStage(db, explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));

assert.eq([1], coll.distinct('b', {a: 1}));
var explain = runDistinctExplain(coll, 'b', {a: 1});
assert.commandWorked(explain);
assert.eq(1, explain.executionStats.nReturned);
assert(!planHasStage(db, explain.queryPlanner.winningPlan, "FETCH"));
assert(planHasStage(db, explain.queryPlanner.winningPlan, "PROJECTION_COVERED"));
assert(planHasStage(db, explain.queryPlanner.winningPlan, "DISTINCT_SCAN"));
})();