summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Zolnierz <nicholas.zolnierz@mongodb.com>2022-09-15 15:11:22 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-10-06 20:30:58 +0000
commitc470abdc3d07d42bd6f78a616559b6f311719c80 (patch)
tree227e5148e2ad559d00b87f76f0185e6bc4fc2836
parent8f45eeaecaa95d38263e8bcc9da6ceeb7aa3d1d2 (diff)
downloadmongo-c470abdc3d07d42bd6f78a616559b6f311719c80.tar.gz
SERVER-69380 Avoid swapping meta projection with $_internalUnpackBucket if a projection has already been absorbed
(cherry picked from commit d1a117a1abc9ead34fc6399697055a46ca0c1df4)
-rw-r--r--jstests/core/timeseries/timeseries_project.js5
-rw-r--r--src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/optimize_pipeline_test.cpp49
3 files changed, 55 insertions, 1 deletions
diff --git a/jstests/core/timeseries/timeseries_project.js b/jstests/core/timeseries/timeseries_project.js
index 4958ded193a..275a213d354 100644
--- a/jstests/core/timeseries/timeseries_project.js
+++ b/jstests/core/timeseries/timeseries_project.js
@@ -118,5 +118,10 @@ pipeline = [{$addFields: {a: "$x", b: "$a"}}, {$project: {_id: 0}}];
tsDoc = tsColl.aggregate(pipeline).toArray();
regDoc = regColl.aggregate(pipeline).toArray();
assert.docEq(tsDoc, regDoc);
+
+pipeline = [{$project: {a: 1, _id: 0}}, {$project: {newMeta: "$x"}}];
+tsDoc = tsColl.aggregate(pipeline).toArray();
+regDoc = regColl.aggregate(pipeline).toArray();
+assert.docEq(tsDoc, regDoc);
})();
})();
diff --git a/src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp b/src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp
index 72251d7a842..a7dc3e7573d 100644
--- a/src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp
+++ b/src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp
@@ -465,7 +465,7 @@ bool DocumentSourceInternalUnpackBucket::pushDownComputedMetaProjection(
if (std::next(itr) == container->end()) {
return nextStageWasRemoved;
}
- if (!_bucketUnpacker.bucketSpec().metaField) {
+ if (!_bucketUnpacker.bucketSpec().metaField || !_bucketUnpacker.includeMetaField()) {
return nextStageWasRemoved;
}
diff --git a/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/optimize_pipeline_test.cpp b/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/optimize_pipeline_test.cpp
index 1f190355cd5..ef61bbaf09b 100644
--- a/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/optimize_pipeline_test.cpp
+++ b/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/optimize_pipeline_test.cpp
@@ -724,6 +724,55 @@ TEST_F(OptimizePipeline, InternalizeProjectAndPushdownAddFields) {
serialized[1]);
}
+TEST_F(OptimizePipeline, DoNotSwapAddFieldsIfDependencyIsExcluded) {
+ {
+ auto unpackSpecObj = fromjson(
+ "{$_internalUnpackBucket: { exclude: [], timeField: 'time', metaField: 'myMeta', "
+ "bucketMaxSpanSeconds: 3600}}");
+ auto projectSpecObj = fromjson("{$project: {x: true, _id: false}}");
+ auto addFieldsSpec = fromjson("{$addFields: {newMeta: '$myMeta'}}");
+
+ auto pipeline =
+ Pipeline::parse(makeVector(unpackSpecObj, projectSpecObj, addFieldsSpec), getExpCtx());
+
+ pipeline->optimizePipeline();
+
+ // We should internalize the $project but _not_ push down the $addFields because it's field
+ // dependency has been excluded. Theoretically we could remove the $addFields for this
+ // trivial except but not always.
+ auto serialized = pipeline->serializeToBson();
+ ASSERT_EQ(2u, serialized.size());
+ ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { include: ['x'], timeField: 'time', "
+ "metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
+ serialized[0]);
+ ASSERT_BSONOBJ_EQ(fromjson("{$addFields: {newMeta: '$myMeta'}}"), serialized[1]);
+ }
+
+ // Similar test except the dependency is on an excluded non-meta field.
+ {
+ auto unpackSpecObj = fromjson(
+ "{$_internalUnpackBucket: { exclude: [], timeField: 'time', metaField: 'myMeta', "
+ "bucketMaxSpanSeconds: 3600}}");
+ auto projectSpecObj = fromjson("{$project: {x: true, _id: false}}");
+ auto addFieldsSpec = fromjson("{$addFields: {newMeta: '$excluded'}}");
+
+ auto pipeline =
+ Pipeline::parse(makeVector(unpackSpecObj, projectSpecObj, addFieldsSpec), getExpCtx());
+
+ pipeline->optimizePipeline();
+
+ // We should internalize the $project but _not_ push down the $addFields because it's field
+ // dependency has been excluded. Theoretically we could remove the $addFields for this
+ // trivial except but not always.
+ auto serialized = pipeline->serializeToBson();
+ ASSERT_EQ(2u, serialized.size());
+ ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { include: ['x'], timeField: 'time', "
+ "metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
+ serialized[0]);
+ ASSERT_BSONOBJ_EQ(fromjson("{$addFields: {newMeta: '$excluded'}}"), serialized[1]);
+ }
+}
+
TEST_F(OptimizePipeline, PushdownSortAndAddFields) {
auto unpackSpecObj = fromjson(
"{$_internalUnpackBucket: { exclude: [], timeField: 'time', metaField: 'myMeta', "