109 lines
3.9 KiB
JavaScript
109 lines
3.9 KiB
JavaScript
// Cannot implicitly shard accessed collections because of collection existing when none
|
|
// expected.
|
|
// @tags: [
|
|
// assumes_no_implicit_collection_creation_after_drop,
|
|
// requires_fcv_81,
|
|
// ]
|
|
|
|
/**
|
|
* This test ensures that explain on the distinct command works.
|
|
*/
|
|
import {
|
|
getPlanStage,
|
|
getPlanStages,
|
|
getWinningPlanFromExplain,
|
|
isCollscan,
|
|
planHasStage
|
|
} from "jstests/libs/query/analyze_plan.js";
|
|
|
|
const collName = "jstests_explain_distinct";
|
|
const coll = db[collName];
|
|
|
|
function runDistinctExplain(collection, keyString, query) {
|
|
const distinctCmd = {distinct: collection.getName(), key: keyString};
|
|
|
|
if (typeof query !== 'undefined') {
|
|
distinctCmd.query = query;
|
|
}
|
|
|
|
return coll.runCommand({explain: distinctCmd, verbosity: 'executionStats'});
|
|
}
|
|
|
|
// Ensure db exists (needed for explain to work).
|
|
db.filler_collection.drop();
|
|
assert.commandWorked(db.createCollection("filler_collection"));
|
|
db.filler_collection.drop();
|
|
|
|
coll.drop();
|
|
|
|
// Collection doesn't exist.
|
|
let explain = runDistinctExplain(coll, 'a', {});
|
|
assert.commandWorked(explain);
|
|
let winningPlan = getWinningPlanFromExplain(explain);
|
|
assert(planHasStage(db, winningPlan, "EOF"));
|
|
const eofStages = getPlanStages(winningPlan, "EOF");
|
|
eofStages.forEach(stage => assert.eq(stage.type, "nonExistentNamespace", explain));
|
|
|
|
// Insert the data to perform distinct() on.
|
|
for (let i = 0; i < 10; i++) {
|
|
assert.commandWorked(coll.insert({a: 1, b: 1}));
|
|
assert.commandWorked(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, 'a', null));
|
|
assert.commandWorked(runDistinctExplain(coll, 'a'));
|
|
|
|
assert.eq([1], coll.distinct('b'));
|
|
explain = runDistinctExplain(coll, 'b', {});
|
|
assert.commandWorked(explain);
|
|
winningPlan = getWinningPlanFromExplain(explain);
|
|
assert.eq(20, explain.executionStats.nReturned);
|
|
assert(isCollscan(db, winningPlan));
|
|
|
|
assert.commandWorked(coll.createIndex({a: 1}));
|
|
|
|
assert.eq([1, 2], coll.distinct('a'));
|
|
explain = runDistinctExplain(coll, 'a', {});
|
|
assert.commandWorked(explain);
|
|
winningPlan = getWinningPlanFromExplain(explain);
|
|
assert.eq(2, explain.executionStats.nReturned);
|
|
assert(planHasStage(db, winningPlan, "PROJECTION_COVERED"));
|
|
assert(planHasStage(db, winningPlan, "DISTINCT_SCAN"));
|
|
|
|
// Check that the DISTINCT_SCAN stage has the correct stats.
|
|
let 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}));
|
|
explain = runDistinctExplain(coll, 'a', {a: 1});
|
|
assert.commandWorked(explain);
|
|
winningPlan = getWinningPlanFromExplain(explain);
|
|
assert.eq(1, explain.executionStats.nReturned);
|
|
assert(planHasStage(db, winningPlan, "PROJECTION_COVERED"));
|
|
assert(planHasStage(db, winningPlan, "DISTINCT_SCAN"));
|
|
|
|
assert.eq([1], coll.distinct('b', {a: 1}));
|
|
explain = runDistinctExplain(coll, 'b', {a: 1});
|
|
assert.commandWorked(explain);
|
|
winningPlan = getWinningPlanFromExplain(explain);
|
|
assert.eq(1, explain.executionStats.nReturned);
|
|
assert(!planHasStage(db, winningPlan, "FETCH"));
|
|
assert(planHasStage(db, winningPlan, "PROJECTION_COVERED"));
|
|
assert(planHasStage(db, winningPlan, "DISTINCT_SCAN"));
|