summaryrefslogtreecommitdiff
path: root/jstests/aggregation/sources/project/remove_redundant_projects.js
diff options
context:
space:
mode:
Diffstat (limited to 'jstests/aggregation/sources/project/remove_redundant_projects.js')
-rw-r--r--jstests/aggregation/sources/project/remove_redundant_projects.js285
1 files changed, 143 insertions, 142 deletions
diff --git a/jstests/aggregation/sources/project/remove_redundant_projects.js b/jstests/aggregation/sources/project/remove_redundant_projects.js
index e3c7af08573..f1a21264c7e 100644
--- a/jstests/aggregation/sources/project/remove_redundant_projects.js
+++ b/jstests/aggregation/sources/project/remove_redundant_projects.js
@@ -2,150 +2,151 @@
// pipeline that can be covered by a normal query.
// @tags: [do_not_wrap_aggregations_in_facets]
(function() {
- "use strict";
-
- load("jstests/aggregation/extras/utils.js"); // For orderedArrayEq.
- load('jstests/libs/analyze_plan.js'); // For planHasStage().
-
- let coll = db.remove_redundant_projects;
- coll.drop();
-
- assert.writeOK(coll.insert({_id: {a: 1, b: 1}, a: 1, c: {d: 1}, e: ['elem1']}));
-
- let indexSpec = {a: 1, 'c.d': 1, 'e.0': 1};
-
- /**
- * Helper to test that for a given pipeline, the same results are returned whether or not an
- * index is present. Also tests whether a projection is absorbed by the pipeline
- * ('expectProjectToCoalesce') and the corresponding project stage ('removedProjectStage') does
- * not exist in the explain output.
- */
- function assertResultsMatch({pipeline = [],
- expectProjectToCoalesce = false,
- removedProjectStage = null,
- index = indexSpec,
- pipelineOptimizedAway = false} = {}) {
- // Add a match stage to ensure index scans are considered for planning (workaround for
- // SERVER-20066).
- pipeline = [{$match: {a: {$gte: 0}}}].concat(pipeline);
-
- // Once with an index.
- assert.commandWorked(coll.createIndex(index));
- let explain = coll.explain().aggregate(pipeline);
- let resultsWithIndex = coll.aggregate(pipeline).toArray();
-
- // Projection does not get pushed down when sharding filter is used.
- if (!explain.hasOwnProperty("shards")) {
- let result;
-
- if (pipelineOptimizedAway) {
- assert(isQueryPlan(explain));
- result = explain.queryPlanner.winningPlan;
- } else {
- assert(isAggregationPlan(explain));
- result = explain.stages[0].$cursor.queryPlanner.winningPlan;
- }
-
- // Check that $project uses the query system.
- assert.eq(expectProjectToCoalesce,
- planHasStage(db, result, "PROJECTION_DEFAULT") ||
- planHasStage(db, result, "PROJECTION_COVERED") ||
- planHasStage(db, result, "PROJECTION_SIMPLE"));
-
- if (!pipelineOptimizedAway) {
- // Check that $project was removed from pipeline and pushed to the query system.
- explain.stages.forEach(function(stage) {
- if (stage.hasOwnProperty("$project"))
- assert.neq(removedProjectStage, stage["$project"]);
- });
- }
+"use strict";
+
+load("jstests/aggregation/extras/utils.js"); // For orderedArrayEq.
+load('jstests/libs/analyze_plan.js'); // For planHasStage().
+
+let coll = db.remove_redundant_projects;
+coll.drop();
+
+assert.writeOK(coll.insert({_id: {a: 1, b: 1}, a: 1, c: {d: 1}, e: ['elem1']}));
+
+let indexSpec = {a: 1, 'c.d': 1, 'e.0': 1};
+
+/**
+ * Helper to test that for a given pipeline, the same results are returned whether or not an
+ * index is present. Also tests whether a projection is absorbed by the pipeline
+ * ('expectProjectToCoalesce') and the corresponding project stage ('removedProjectStage') does
+ * not exist in the explain output.
+ */
+function assertResultsMatch({
+ pipeline = [],
+ expectProjectToCoalesce = false,
+ removedProjectStage = null,
+ index = indexSpec,
+ pipelineOptimizedAway = false
+} = {}) {
+ // Add a match stage to ensure index scans are considered for planning (workaround for
+ // SERVER-20066).
+ pipeline = [{$match: {a: {$gte: 0}}}].concat(pipeline);
+
+ // Once with an index.
+ assert.commandWorked(coll.createIndex(index));
+ let explain = coll.explain().aggregate(pipeline);
+ let resultsWithIndex = coll.aggregate(pipeline).toArray();
+
+ // Projection does not get pushed down when sharding filter is used.
+ if (!explain.hasOwnProperty("shards")) {
+ let result;
+
+ if (pipelineOptimizedAway) {
+ assert(isQueryPlan(explain));
+ result = explain.queryPlanner.winningPlan;
+ } else {
+ assert(isAggregationPlan(explain));
+ result = explain.stages[0].$cursor.queryPlanner.winningPlan;
}
- // Again without an index.
- assert.commandWorked(coll.dropIndex(index));
- let resultsWithoutIndex = coll.aggregate(pipeline).toArray();
-
- assert(orderedArrayEq(resultsWithIndex, resultsWithoutIndex));
+ // Check that $project uses the query system.
+ assert.eq(expectProjectToCoalesce,
+ planHasStage(db, result, "PROJECTION_DEFAULT") ||
+ planHasStage(db, result, "PROJECTION_COVERED") ||
+ planHasStage(db, result, "PROJECTION_SIMPLE"));
+
+ if (!pipelineOptimizedAway) {
+ // Check that $project was removed from pipeline and pushed to the query system.
+ explain.stages.forEach(function(stage) {
+ if (stage.hasOwnProperty("$project"))
+ assert.neq(removedProjectStage, stage["$project"]);
+ });
+ }
}
- // Test that covered projections correctly use the query system for projection and the $project
- // stage is removed from the pipeline.
- assertResultsMatch({
- pipeline: [{$project: {_id: 0, a: 1}}],
- expectProjectToCoalesce: true,
- removedProjectStage: {_id: 0, a: 1},
- pipelineOptimizedAway: true
- });
- assertResultsMatch({
- pipeline: [{$project: {_id: 0, a: 1}}, {$group: {_id: null, a: {$sum: "$a"}}}],
- expectProjectToCoalesce: true,
- removedProjectStage: {_id: 0, a: 1}
- });
- assertResultsMatch({
- pipeline: [{$sort: {a: -1}}, {$project: {_id: 0, a: 1}}],
- expectProjectToCoalesce: true,
- removedProjectStage: {_id: 0, a: 1},
- pipelineOptimizedAway: true
- });
- assertResultsMatch({
- pipeline: [
- {$sort: {a: 1, 'c.d': 1}},
- {$project: {_id: 0, a: 1}},
- {$group: {_id: "$a", arr: {$push: "$a"}}}
- ],
- expectProjectToCoalesce: true,
- removedProjectStage: {_id: 0, a: 1}
- });
- assertResultsMatch({
- pipeline: [{$project: {_id: 0, c: {d: 1}}}],
- expectProjectToCoalesce: true,
- removedProjectStage: {_id: 0, c: {d: 1}},
- pipelineOptimizedAway: true
- });
-
- // Test that projections with renamed fields are not removed from the pipeline, however an
- // inclusion projection is still pushed to the query system.
- assertResultsMatch({pipeline: [{$project: {_id: 0, f: "$a"}}], expectProjectToCoalesce: true});
- assertResultsMatch(
- {pipeline: [{$project: {_id: 0, a: 1, f: "$a"}}], expectProjectToCoalesce: true});
-
- // Test that uncovered projections include the $project stage in the pipeline.
- assertResultsMatch(
- {pipeline: [{$sort: {a: 1}}, {$project: {_id: 1, b: 1}}], expectProjectToCoalesce: false});
- assertResultsMatch({
- pipeline:
- [{$sort: {a: 1}}, {$group: {_id: "$_id", arr: {$push: "$a"}}}, {$project: {arr: 1}}],
- expectProjectToCoalesce: false
- });
-
- // Test that projections with computed fields are kept in the pipeline.
- assertResultsMatch(
- {pipeline: [{$project: {computedField: {$sum: "$a"}}}], expectProjectToCoalesce: false});
- assertResultsMatch({pipeline: [{$project: {a: ["$a", "$b"]}}], expectProjectToCoalesce: false});
- assertResultsMatch({
- pipeline: [{
- $project:
- {e: {$filter: {input: "$e", as: "item", cond: {"$eq": ["$$item", "elem0"]}}}}
- }],
- expectProjectToCoalesce: false
- });
-
- // Test that only the first projection is removed from the pipeline.
- assertResultsMatch({
- pipeline: [
- {$project: {_id: 0, a: 1}},
- {$group: {_id: "$a", arr: {$push: "$a"}, a: {$sum: "$a"}}},
- {$project: {_id: 0}}
- ],
- expectProjectToCoalesce: true,
- removedProjectStage: {_id: 0, a: 1}
- });
-
- // Test that projections on _id with nested fields are not removed from pipeline. Due to
- // SERVER-7502, the dependency analysis does not generate a covered projection for nested
- // fields in _id and thus we cannot remove the stage.
- indexSpec = {'_id.a': 1, a: 1};
- assertResultsMatch(
- {pipeline: [{$project: {'_id.a': 1}}], expectProjectToCoalesce: false, index: indexSpec});
-
+ // Again without an index.
+ assert.commandWorked(coll.dropIndex(index));
+ let resultsWithoutIndex = coll.aggregate(pipeline).toArray();
+
+ assert(orderedArrayEq(resultsWithIndex, resultsWithoutIndex));
+}
+
+// Test that covered projections correctly use the query system for projection and the $project
+// stage is removed from the pipeline.
+assertResultsMatch({
+ pipeline: [{$project: {_id: 0, a: 1}}],
+ expectProjectToCoalesce: true,
+ removedProjectStage: {_id: 0, a: 1},
+ pipelineOptimizedAway: true
+});
+assertResultsMatch({
+ pipeline: [{$project: {_id: 0, a: 1}}, {$group: {_id: null, a: {$sum: "$a"}}}],
+ expectProjectToCoalesce: true,
+ removedProjectStage: {_id: 0, a: 1}
+});
+assertResultsMatch({
+ pipeline: [{$sort: {a: -1}}, {$project: {_id: 0, a: 1}}],
+ expectProjectToCoalesce: true,
+ removedProjectStage: {_id: 0, a: 1},
+ pipelineOptimizedAway: true
+});
+assertResultsMatch({
+ pipeline: [
+ {$sort: {a: 1, 'c.d': 1}},
+ {$project: {_id: 0, a: 1}},
+ {$group: {_id: "$a", arr: {$push: "$a"}}}
+ ],
+ expectProjectToCoalesce: true,
+ removedProjectStage: {_id: 0, a: 1}
+});
+assertResultsMatch({
+ pipeline: [{$project: {_id: 0, c: {d: 1}}}],
+ expectProjectToCoalesce: true,
+ removedProjectStage: {_id: 0, c: {d: 1}},
+ pipelineOptimizedAway: true
+});
+
+// Test that projections with renamed fields are not removed from the pipeline, however an
+// inclusion projection is still pushed to the query system.
+assertResultsMatch({pipeline: [{$project: {_id: 0, f: "$a"}}], expectProjectToCoalesce: true});
+assertResultsMatch(
+ {pipeline: [{$project: {_id: 0, a: 1, f: "$a"}}], expectProjectToCoalesce: true});
+
+// Test that uncovered projections include the $project stage in the pipeline.
+assertResultsMatch(
+ {pipeline: [{$sort: {a: 1}}, {$project: {_id: 1, b: 1}}], expectProjectToCoalesce: false});
+assertResultsMatch({
+ pipeline: [{$sort: {a: 1}}, {$group: {_id: "$_id", arr: {$push: "$a"}}}, {$project: {arr: 1}}],
+ expectProjectToCoalesce: false
+});
+
+// Test that projections with computed fields are kept in the pipeline.
+assertResultsMatch(
+ {pipeline: [{$project: {computedField: {$sum: "$a"}}}], expectProjectToCoalesce: false});
+assertResultsMatch({pipeline: [{$project: {a: ["$a", "$b"]}}], expectProjectToCoalesce: false});
+assertResultsMatch({
+ pipeline:
+ [{$project: {e: {$filter: {input: "$e", as: "item", cond: {"$eq": ["$$item", "elem0"]}}}}}],
+ expectProjectToCoalesce: false
+});
+
+// Test that only the first projection is removed from the pipeline.
+assertResultsMatch({
+ pipeline: [
+ {$project: {_id: 0, a: 1}},
+ {$group: {_id: "$a", arr: {$push: "$a"}, a: {$sum: "$a"}}},
+ {$project: {_id: 0}}
+ ],
+ expectProjectToCoalesce: true,
+ removedProjectStage: {_id: 0, a: 1}
+});
+
+// Test that projections on _id with nested fields are not removed from pipeline. Due to
+// SERVER-7502, the dependency analysis does not generate a covered projection for nested
+// fields in _id and thus we cannot remove the stage.
+indexSpec = {
+ '_id.a': 1,
+ a: 1
+};
+assertResultsMatch(
+ {pipeline: [{$project: {'_id.a': 1}}], expectProjectToCoalesce: false, index: indexSpec});
}());