summaryrefslogtreecommitdiff
path: root/jstests/core/explain_count.js
blob: 4943c511252cd1ed12d302b287be74c9f9f238a6 (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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Test running explains on count commands.

var collName = "jstests_explain_count";
var t = db[collName];
t.drop();

/**
 * Given explain output 'explain' at executionStats level verbosity,
 * confirms that the root stage is COUNT and that the result of the
 * count is equal to 'nCounted'.
 */
function checkCountExplain(explain, nCounted) {
    printjson(explain);
    var execStages = explain.executionStats.executionStages;

    // If passed through mongos, then the root stage should be the mongos SINGLE_SHARD stage,
    // with COUNT as its child. If explaining directly on the shard, then COUNT is the root
    // stage.
    if ("SINGLE_SHARD" == execStages.stage) {
        var countStage = execStages.shards[0].executionStages;
        assert.eq(countStage.stage, "COUNT", "root stage on shard is not COUNT");
        assert.eq(countStage.nCounted, nCounted, "wrong count result");
    } else {
        assert.eq(execStages.stage, "COUNT", "root stage is not COUNT");
        assert.eq(execStages.nCounted, nCounted, "wrong count result");
    }
}

// Collection does not exist.
assert.eq(0, t.count());
var explain = db.runCommand({explain: {count: collName}, verbosity: "executionStats"});
checkCountExplain(explain, 0);

// Collection does not exist with skip, limit, and/or query.
assert.eq(0, db.runCommand({count: collName, skip: 3}).n);
explain = db.runCommand({explain: {count: collName, skip: 3}, verbosity: "executionStats"});
checkCountExplain(explain, 0);

assert.eq(0, db.runCommand({count: collName, limit: 3}).n);
explain = db.runCommand({explain: {count: collName, limit: 3}, verbosity: "executionStats"});
checkCountExplain(explain, 0);

assert.eq(0, db.runCommand({count: collName, limit: -3}).n);
explain = db.runCommand({explain: {count: collName, limit: -3}, verbosity: "executionStats"});
checkCountExplain(explain, 0);

assert.eq(0, db.runCommand({count: collName, limit: -3, skip: 4}).n);
explain =
    db.runCommand({explain: {count: collName, limit: -3, skip: 4}, verbosity: "executionStats"});
checkCountExplain(explain, 0);

assert.eq(0, db.runCommand({count: collName, query: {a: 1}, limit: -3, skip: 4}).n);
explain = db.runCommand(
    {explain: {count: collName, query: {a: 1}, limit: -3, skip: 4}, verbosity: "executionStats"});
checkCountExplain(explain, 0);

// Now add a bit of data to the collection.
t.ensureIndex({a: 1});
for (var i = 0; i < 10; i++) {
    t.insert({_id: i, a: 1});
}

// Trivial count with no skip, limit, or query.
assert.eq(10, t.count());
explain = db.runCommand({explain: {count: collName}, verbosity: "executionStats"});
checkCountExplain(explain, 10);

// Trivial count with skip.
assert.eq(7, db.runCommand({count: collName, skip: 3}).n);
explain = db.runCommand({explain: {count: collName, skip: 3}, verbosity: "executionStats"});
checkCountExplain(explain, 7);

// Trivial count with limit.
assert.eq(3, db.runCommand({count: collName, limit: 3}).n);
explain = db.runCommand({explain: {count: collName, limit: 3}, verbosity: "executionStats"});
checkCountExplain(explain, 3);

// Trivial count with negative limit.
assert.eq(3, db.runCommand({count: collName, limit: -3}).n);
explain = db.runCommand({explain: {count: collName, limit: -3}, verbosity: "executionStats"});
checkCountExplain(explain, 3);

// Trivial count with both limit and skip.
assert.eq(3, db.runCommand({count: collName, limit: -3, skip: 4}).n);
explain =
    db.runCommand({explain: {count: collName, limit: -3, skip: 4}, verbosity: "executionStats"});
checkCountExplain(explain, 3);

// With a query.
assert.eq(10, db.runCommand({count: collName, query: {a: 1}}).n);
explain = db.runCommand({explain: {count: collName, query: {a: 1}}, verbosity: "executionStats"});
checkCountExplain(explain, 10);

// With a query and skip.
assert.eq(7, db.runCommand({count: collName, query: {a: 1}, skip: 3}).n);
explain = db.runCommand(
    {explain: {count: collName, query: {a: 1}, skip: 3}, verbosity: "executionStats"});
checkCountExplain(explain, 7);

// With a query and limit.
assert.eq(3, db.runCommand({count: collName, query: {a: 1}, limit: 3}).n);
explain = db.runCommand(
    {explain: {count: collName, query: {a: 1}, limit: 3}, verbosity: "executionStats"});
checkCountExplain(explain, 3);

// Insert one more doc for the last few tests.
t.insert({a: 2});

// Case where all results are skipped.
assert.eq(0, db.runCommand({count: collName, query: {a: 2}, skip: 2}).n);
explain = db.runCommand(
    {explain: {count: collName, query: {a: 2}, skip: 2}, verbosity: "executionStats"});
checkCountExplain(explain, 0);

// Case where we have a limit, but we don't hit it.
assert.eq(1, db.runCommand({count: collName, query: {a: 2}, limit: 2}).n);
explain = db.runCommand(
    {explain: {count: collName, query: {a: 2}, limit: 2}, verbosity: "executionStats"});
checkCountExplain(explain, 1);