summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Evans <jacob.evans@10gen.com>2021-04-20 23:02:58 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-04-21 03:28:32 +0000
commit384c41b1f89412b5843b8546b8ddf4fcb837eff5 (patch)
tree8e7843faf14c723ce0e9a966053763bbf22f99f5
parent1eadaf115d098198845026aef15b0f24578b46b8 (diff)
downloadmongo-384c41b1f89412b5843b8546b8ddf4fcb837eff5.tar.gz
SERVER-55099 Update $_internalUnpackBucket serialization and parsing
-rw-r--r--src/mongo/db/exec/bucket_unpacker.h6
-rw-r--r--src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp46
-rw-r--r--src/mongo/db/pipeline/document_source_internal_unpack_bucket.h1
-rw-r--r--src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/internalize_project_test.cpp6
-rw-r--r--src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/optimize_pipeline_test.cpp102
-rw-r--r--src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/pushdown_computed_meta_projections_test.cpp28
-rw-r--r--src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/sample_reorder_test.cpp14
-rw-r--r--src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/unpack_bucket_exec_test.cpp33
8 files changed, 174 insertions, 62 deletions
diff --git a/src/mongo/db/exec/bucket_unpacker.h b/src/mongo/db/exec/bucket_unpacker.h
index 9c505bc1682..fd159092efa 100644
--- a/src/mongo/db/exec/bucket_unpacker.h
+++ b/src/mongo/db/exec/bucket_unpacker.h
@@ -29,6 +29,7 @@
#pragma once
+#include <algorithm>
#include <set>
#include "mongo/bson/bsonobj.h"
@@ -182,7 +183,10 @@ private:
*/
inline bool eraseMetaFromFieldSetAndDetermineIncludeMeta(BucketUnpacker::Behavior unpackerBehavior,
BucketSpec* bucketSpec) {
- if (!bucketSpec->metaField) {
+ if (!bucketSpec->metaField ||
+ std::find(bucketSpec->computedMetaProjFields.cbegin(),
+ bucketSpec->computedMetaProjFields.cend(),
+ *bucketSpec->metaField) != bucketSpec->computedMetaProjFields.cend()) {
return false;
} else if (auto itr = bucketSpec->fieldSet.find(*bucketSpec->metaField);
itr != bucketSpec->fieldSet.end()) {
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 664028e21be..4eb1d2ac615 100644
--- a/src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp
+++ b/src/mongo/db/pipeline/document_source_internal_unpack_bucket.cpp
@@ -31,6 +31,9 @@
#include "mongo/platform/basic.h"
+#include <algorithm>
+#include <iterator>
+
#include "mongo/db/pipeline/document_source_internal_unpack_bucket.h"
#include <string>
@@ -287,6 +290,7 @@ boost::intrusive_ptr<DocumentSource> DocumentSourceInternalUnpackBucket::createF
auto hasIncludeExclude = false;
std::vector<std::string> fields;
auto bucketMaxSpanSeconds = 0;
+ std::vector<std::string> computedMetaProjFields;
for (auto&& elem : specElem.embeddedObject()) {
auto fieldName = elem.fieldNameStringData();
if (fieldName == "include" || fieldName == "exclude") {
@@ -325,13 +329,28 @@ boost::intrusive_ptr<DocumentSource> DocumentSourceInternalUnpackBucket::createF
metaField.find('.') == std::string::npos);
bucketSpec.metaField = std::move(metaField);
} else if (fieldName == "bucketMaxSpanSeconds") {
- uassert(5509900,
+ uassert(5510600,
"bucketMaxSpanSeconds field must be an integer",
elem.type() == BSONType::NumberInt);
- uassert(5509901,
+ uassert(5510601,
"bucketMaxSpanSeconds field must be greater than zero",
elem._numberInt() > 0);
bucketMaxSpanSeconds = elem._numberInt();
+ } else if (fieldName == "computedMetaProjFields") {
+ uassert(5509900,
+ "computedMetaProjFields field must be an array",
+ elem.type() == BSONType::Array);
+
+ for (auto&& elt : elem.embeddedObject()) {
+ uassert(5509901,
+ "computedMetaProjFields field element must be a string",
+ elt.type() == BSONType::String);
+ auto field = elt.valueStringData();
+ uassert(5509902,
+ "computedMetaProjFields field element must be a single-element field path",
+ field.find('.') == std::string::npos);
+ bucketSpec.computedMetaProjFields.emplace_back(field);
+ }
} else {
uasserted(5346506,
str::stream()
@@ -343,7 +362,7 @@ boost::intrusive_ptr<DocumentSource> DocumentSourceInternalUnpackBucket::createF
"The $_internalUnpackBucket stage requires a timeField parameter",
specElem[timeseries::kTimeFieldName].ok());
- uassert(5509902,
+ uassert(5510602,
"The $_internalUnpackBucket stage requires a bucketMaxSpanSeconds parameter",
specElem["bucketMaxSpanSeconds"].ok());
@@ -361,13 +380,32 @@ void DocumentSourceInternalUnpackBucket::serializeToArray(
for (auto&& field : spec.fieldSet) {
fields.emplace_back(field);
}
- out.addField(behavior, Value{fields});
+ if (((_bucketUnpacker.includeMetaField() &&
+ _bucketUnpacker.behavior() == BucketUnpacker::Behavior::kInclude) ||
+ (!_bucketUnpacker.includeMetaField() &&
+ _bucketUnpacker.behavior() == BucketUnpacker::Behavior::kExclude && spec.metaField)) &&
+ std::find(spec.computedMetaProjFields.cbegin(),
+ spec.computedMetaProjFields.cend(),
+ *spec.metaField) == spec.computedMetaProjFields.cend())
+ fields.emplace_back(*spec.metaField);
+
+ out.addField(behavior, Value{std::move(fields)});
out.addField(timeseries::kTimeFieldName, Value{spec.timeField});
if (spec.metaField) {
out.addField(timeseries::kMetaFieldName, Value{*spec.metaField});
}
out.addField("bucketMaxSpanSeconds", Value{_bucketMaxSpanSeconds});
+ if (!spec.computedMetaProjFields.empty())
+ out.addField("computedMetaProjFields", Value{[&] {
+ std::vector<Value> compFields;
+ std::transform(spec.computedMetaProjFields.cbegin(),
+ spec.computedMetaProjFields.cend(),
+ std::back_inserter(compFields),
+ [](auto&& projString) { return Value{projString}; });
+ return compFields;
+ }()});
+
if (!explain) {
array.push_back(Value(DOC(getSourceName() << out.freeze())));
if (_sampleSize) {
diff --git a/src/mongo/db/pipeline/document_source_internal_unpack_bucket.h b/src/mongo/db/pipeline/document_source_internal_unpack_bucket.h
index c7dc7ccb0a4..171547cd4d8 100644
--- a/src/mongo/db/pipeline/document_source_internal_unpack_bucket.h
+++ b/src/mongo/db/pipeline/document_source_internal_unpack_bucket.h
@@ -30,6 +30,7 @@
#pragma once
#include <set>
+#include <vector>
#include "mongo/db/exec/bucket_unpacker.h"
#include "mongo/db/pipeline/document_source.h"
diff --git a/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/internalize_project_test.cpp b/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/internalize_project_test.cpp
index 8151a279242..5366e6789ce 100644
--- a/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/internalize_project_test.cpp
+++ b/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/internalize_project_test.cpp
@@ -157,8 +157,8 @@ TEST_F(InternalUnpackBucketInternalizeProjectTest,
std::vector<Value> serializedArray;
unpack->serializeToArray(serializedArray);
- ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { include: ['_id'], timeField: 'time', "
- "metaField: 'meta', bucketMaxSpanSeconds: 3600}}"),
+ ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { include: ['_id', 'meta'], timeField: "
+ "'time', metaField: 'meta', bucketMaxSpanSeconds: 3600}}"),
serializedArray[0].getDocument().toBson());
ASSERT_TRUE(unpack->includeMetaField());
ASSERT_FALSE(unpack->includeTimeField());
@@ -177,7 +177,7 @@ TEST_F(InternalUnpackBucketInternalizeProjectTest,
std::vector<Value> serializedArray;
unpack->serializeToArray(serializedArray);
- ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { exclude: [], timeField: 'time', "
+ ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { exclude: ['myMeta'], timeField: 'time', "
"metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
serializedArray[0].getDocument().toBson());
ASSERT_FALSE(unpack->includeMetaField());
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 6f0978011c1..17077b428ed 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
@@ -346,9 +346,10 @@ TEST_F(OptimizePipeline, ProjectThenMixedMatchPushedDown) {
fromjson(
"{$match: {$and: [{meta: {$eq: 'abc'}}, {'control.min.a': {$_internalExprLte: 4}}]}}"),
stages[0].getDocument().toBson());
- ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { include: ['_id', 'a', 'x'], timeField: "
- "'time', metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
- stages[1].getDocument().toBson());
+ ASSERT_BSONOBJ_EQ(
+ fromjson("{$_internalUnpackBucket: { include: ['_id', 'a', 'x', 'myMeta'], timeField: "
+ "'time', metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
+ stages[1].getDocument().toBson());
ASSERT_BSONOBJ_EQ(fromjson("{$match: {a: {$lte: 4}}}"), stages[2].getDocument().toBson());
const UnorderedFieldsBSONObjComparator kComparator;
ASSERT_EQ(
@@ -401,9 +402,10 @@ TEST_F(OptimizePipeline, ComputedProjectThenMetaMatchPushedDown) {
ASSERT_EQ(3u, serialized.size());
ASSERT_BSONOBJ_EQ(fromjson("{$match: {meta: {$gte: 'abc'}}}"), serialized[0]);
ASSERT_BSONOBJ_EQ(fromjson("{$addFields: {y: '$meta'}}"), serialized[1]);
- ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { include: ['_id', 'y'], timeField: "
- "'time', metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
- serialized[2]);
+ ASSERT_BSONOBJ_EQ(
+ fromjson("{$_internalUnpackBucket: { include: ['_id', 'y'], timeField: 'time', metaField: "
+ "'myMeta', bucketMaxSpanSeconds: 3600, computedMetaProjFields: ['y']}}"),
+ serialized[2]);
}
TEST_F(OptimizePipeline, ComputedProjectThenMetaMatchNotPushedDown) {
@@ -423,11 +425,13 @@ TEST_F(OptimizePipeline, ComputedProjectThenMetaMatchNotPushedDown) {
ASSERT_EQ(3u, serialized.size());
ASSERT_BSONOBJ_EQ(fromjson("{$addFields: {myMeta: {$sum: ['$meta.a', '$meta.b']}}}"),
serialized[0]);
- ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { include: ['_id'], timeField: "
- "'time', metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
- serialized[1]);
+ ASSERT_BSONOBJ_EQ(
+ fromjson(
+ "{$_internalUnpackBucket: { include: ['_id', 'myMeta'], timeField: 'time', metaField: "
+ "'myMeta', bucketMaxSpanSeconds: 3600, computedMetaProjFields: ['myMeta']}}"),
+ serialized[1]);
ASSERT_BSONOBJ_EQ(fromjson("{$match: {myMeta: {$gte: 'abc'}}}"), serialized[2]);
-}
+} // namespace
TEST_F(OptimizePipeline, ComputedProjectThenMatchNotPushedDown) {
auto pipeline = Pipeline::parse(
@@ -445,9 +449,10 @@ TEST_F(OptimizePipeline, ComputedProjectThenMatchNotPushedDown) {
auto serialized = pipeline->serializeToBson();
ASSERT_EQ(3u, serialized.size());
ASSERT_BSONOBJ_EQ(fromjson("{$addFields: {y: {$sum: ['$meta.a', '$meta.b']}}}"), serialized[0]);
- ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { include: ['_id', 'y'], timeField: "
- "'time', metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
- serialized[1]);
+ ASSERT_BSONOBJ_EQ(
+ fromjson("{$_internalUnpackBucket: { include: ['_id', 'y'], timeField: 'time', metaField: "
+ "'myMeta', bucketMaxSpanSeconds: 3600, computedMetaProjFields: ['y']}}"),
+ serialized[1]);
ASSERT_BSONOBJ_EQ(fromjson("{$match: {y: {$gt: 'abc'}}}"), serialized[2]);
}
@@ -466,9 +471,10 @@ TEST_F(OptimizePipeline, MetaSortThenProjectPushedDown) {
auto serialized = pipeline->serializeToBson();
ASSERT_EQ(2u, serialized.size());
ASSERT_BSONOBJ_EQ(fromjson("{$sort: {meta: -1}}"), serialized[0]);
- ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { include: ['_id', 'x'], timeField: "
- "'time', metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
- serialized[1]);
+ ASSERT_BSONOBJ_EQ(
+ fromjson("{$_internalUnpackBucket: { include: ['_id', 'x', 'myMeta'], timeField: 'time', "
+ "metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
+ serialized[1]);
}
TEST_F(OptimizePipeline, ProjectThenMetaSortPushedDown) {
@@ -486,9 +492,10 @@ TEST_F(OptimizePipeline, ProjectThenMetaSortPushedDown) {
auto serialized = pipeline->serializeToBson();
ASSERT_EQ(2u, serialized.size());
ASSERT_BSONOBJ_EQ(fromjson("{$sort: {meta: -1}}"), serialized[0]);
- ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { include: ['_id', 'x'], timeField: "
- "'time', metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
- serialized[1]);
+ ASSERT_BSONOBJ_EQ(
+ fromjson("{$_internalUnpackBucket: { include: ['_id', 'x', 'myMeta'], timeField: 'time', "
+ "metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
+ serialized[1]);
}
TEST_F(OptimizePipeline, ComputedProjectThenSortPushedDown) {
@@ -507,9 +514,11 @@ TEST_F(OptimizePipeline, ComputedProjectThenSortPushedDown) {
auto serialized = pipeline->serializeToBson();
ASSERT_EQ(3u, serialized.size());
ASSERT_BSONOBJ_EQ(fromjson("{$addFields: {myMeta: '$meta.a'}}"), serialized[0]);
- ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { include: ['_id'], timeField: 'time', "
- "metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
- serialized[1]);
+ ASSERT_BSONOBJ_EQ(
+ fromjson(
+ "{$_internalUnpackBucket: { include: ['_id', 'myMeta'], timeField: 'time', metaField: "
+ "'myMeta', bucketMaxSpanSeconds: 3600, computedMetaProjFields: ['myMeta']}}"),
+ serialized[1]);
ASSERT_BSONOBJ_EQ(fromjson("{$sort: {myMeta: 1}}"), serialized[2]);
}
@@ -552,9 +561,11 @@ TEST_F(OptimizePipeline, ComputedProjectThenProjectPushDown) {
auto serialized = pipeline->serializeToBson();
ASSERT_EQ(3u, serialized.size());
ASSERT_BSONOBJ_EQ(fromjson("{$addFields: {myMeta: '$meta.a'}}"), serialized[0]);
- ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { include: ['_id'], timeField: 'time', "
- "metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
- serialized[1]);
+ ASSERT_BSONOBJ_EQ(
+ fromjson(
+ "{$_internalUnpackBucket: { include: ['_id', 'myMeta'], timeField: 'time', metaField: "
+ "'myMeta', bucketMaxSpanSeconds: 3600, computedMetaProjFields: ['myMeta']}}"),
+ serialized[1]);
ASSERT_BSONOBJ_EQ(fromjson("{$project: {myMeta: false, _id: true}}"), serialized[2]);
}
@@ -573,9 +584,10 @@ TEST_F(OptimizePipeline, AddFieldsThenSortPushedDown) {
auto serialized = pipeline->serializeToBson();
ASSERT_EQ(3u, serialized.size());
ASSERT_BSONOBJ_EQ(fromjson("{$addFields: {myMeta: '$meta.a'}}"), serialized[0]);
- ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { exclude: [], timeField: 'time', "
- "metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
- serialized[1]);
+ ASSERT_BSONOBJ_EQ(
+ fromjson("{$_internalUnpackBucket: { exclude: [], timeField: 'time', metaField: 'myMeta', "
+ "bucketMaxSpanSeconds: 3600, computedMetaProjFields: ['myMeta']}}"),
+ serialized[1]);
ASSERT_BSONOBJ_EQ(fromjson("{$sort: {myMeta: 1}}"), serialized[2]);
}
@@ -595,10 +607,10 @@ TEST_F(OptimizePipeline, PushDownAddFieldsAndInternalizeProjection) {
auto serialized = pipeline->serializeToBson();
ASSERT_EQ(2u, serialized.size());
ASSERT_BSONOBJ_EQ(fromjson("{$addFields: {device: '$meta.a'}}"), serialized[0]);
- ASSERT_BSONOBJ_EQ(
- fromjson("{$_internalUnpackBucket: { include: ['_id', 'device', 'x'], "
- "timeField: 'time', metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
- serialized[1]);
+ ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { include: ['_id', 'device', 'x'], "
+ "timeField: 'time', metaField: 'myMeta', bucketMaxSpanSeconds: "
+ "3600, computedMetaProjFields: ['device']}}"),
+ serialized[1]);
}
TEST_F(OptimizePipeline, PushDownAddFieldsDoNotInternalizeProjection) {
@@ -619,8 +631,8 @@ TEST_F(OptimizePipeline, PushDownAddFieldsDoNotInternalizeProjection) {
ASSERT_EQ(4u, serialized.size());
ASSERT_BSONOBJ_EQ(fromjson("{$addFields: {device: '$meta.a'}}"), serialized[0]);
ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { include: ['_id', 'device', 'x', 'y', "
- "'z'], timeField: 'time', "
- "metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
+ "'z'], timeField: 'time', metaField: 'myMeta', "
+ "bucketMaxSpanSeconds: 3600, computedMetaProjFields: ['device']}}"),
serialized[1]);
ASSERT_BSONOBJ_EQ(fromjson("{$addFields: {z: {$add : ['$x', '$y']}}}"), serialized[2]);
const UnorderedFieldsBSONObjComparator kComparator;
@@ -646,10 +658,10 @@ TEST_F(OptimizePipeline, InternalizeProjectAndPushdownAddFields) {
auto serialized = pipeline->serializeToBson();
ASSERT_EQ(2u, serialized.size());
ASSERT_BSONOBJ_EQ(fromjson("{$addFields: {newMeta: '$meta.a'}}"), serialized[0]);
- ASSERT_BSONOBJ_EQ(
- fromjson("{$_internalUnpackBucket: { include: ['_id', 'newMeta', 'x', 'y'], "
- "timeField: 'time', metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
- serialized[1]);
+ ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { include: ['_id', 'newMeta', 'x', 'y', "
+ "'myMeta'], timeField: 'time', metaField: 'myMeta', "
+ "bucketMaxSpanSeconds: 3600, computedMetaProjFields: ['newMeta']}}"),
+ serialized[1]);
}
TEST_F(OptimizePipeline, PushdownSortAndAddFields) {
@@ -667,9 +679,10 @@ TEST_F(OptimizePipeline, PushdownSortAndAddFields) {
ASSERT_EQ(3u, serialized.size());
ASSERT_BSONOBJ_EQ(fromjson("{$addFields: {newMeta: '$meta.a'}}"), serialized[0]);
ASSERT_BSONOBJ_EQ(fromjson("{$sort: {meta: -1}}"), serialized[1]);
- ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { exclude: [], timeField: 'time', "
- "metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
- serialized[2]);
+ ASSERT_BSONOBJ_EQ(
+ fromjson("{$_internalUnpackBucket: { exclude: [], timeField: 'time', metaField: 'myMeta', "
+ "bucketMaxSpanSeconds: 3600, computedMetaProjFields: ['newMeta']}}"),
+ serialized[2]);
}
TEST_F(OptimizePipeline, PushdownMatchAndAddFields) {
@@ -689,9 +702,10 @@ TEST_F(OptimizePipeline, PushdownMatchAndAddFields) {
ASSERT_EQ(4u, serialized.size());
ASSERT_BSONOBJ_EQ(fromjson("{$match: {'meta.a': {$eq: 'abc'}}}"), serialized[0]);
ASSERT_BSONOBJ_EQ(fromjson("{$addFields: {newMeta: '$meta.b'}}"), serialized[1]);
- ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { exclude: [], timeField: 'time', "
- "metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
- serialized[2]);
+ ASSERT_BSONOBJ_EQ(
+ fromjson("{$_internalUnpackBucket: { exclude: [], timeField: 'time', metaField: 'myMeta', "
+ "bucketMaxSpanSeconds: 3600, computedMetaProjFields: ['newMeta']}}"),
+ serialized[2]);
ASSERT_BSONOBJ_EQ(fromjson("{$addFields: {z: {$add : ['$x', '$y']}}}"), serialized[3]);
}
} // namespace
diff --git a/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/pushdown_computed_meta_projections_test.cpp b/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/pushdown_computed_meta_projections_test.cpp
index 47d7de0b8c0..3f34f8cc345 100644
--- a/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/pushdown_computed_meta_projections_test.cpp
+++ b/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/pushdown_computed_meta_projections_test.cpp
@@ -59,7 +59,10 @@ TEST_F(InternalUnpackBucketPushdownProjectionsTest,
auto serialized = pipeline->serializeToBson();
ASSERT_EQ(2u, serialized.size());
ASSERT_BSONOBJ_EQ(fromjson("{$addFields: {newMeta: {$toUpper: ['$meta']}}}"), serialized[0]);
- ASSERT_BSONOBJ_EQ(unpackSpecObj, serialized[1]);
+ auto extraField = fromjson("{computedMetaProjFields: ['newMeta']}");
+ ASSERT_BSONOBJ_EQ(BSON("$_internalUnpackBucket" << unpackSpecObj.firstElement().Obj().addField(
+ extraField.firstElement())),
+ serialized[1]);
}
TEST_F(InternalUnpackBucketPushdownProjectionsTest, OptimizeAddFieldsWithMetaProjectionDocument) {
@@ -79,7 +82,10 @@ TEST_F(InternalUnpackBucketPushdownProjectionsTest, OptimizeAddFieldsWithMetaPro
ASSERT_EQ(2u, serialized.size());
ASSERT_BSONOBJ_EQ(fromjson("{$addFields: {newMeta: {$concat: ['$meta.a', '$meta.b']}}}"),
serialized[0]);
- ASSERT_BSONOBJ_EQ(unpackSpecObj, serialized[1]);
+ auto extraField = fromjson("{computedMetaProjFields: ['newMeta']}");
+ ASSERT_BSONOBJ_EQ(BSON("$_internalUnpackBucket" << unpackSpecObj.firstElement().Obj().addField(
+ extraField.firstElement())),
+ serialized[1]);
}
TEST_F(InternalUnpackBucketPushdownProjectionsTest, OptimizeAddFieldsWith2MetaProjections) {
@@ -99,7 +105,10 @@ TEST_F(InternalUnpackBucketPushdownProjectionsTest, OptimizeAddFieldsWith2MetaPr
ASSERT_EQ(2u, serialized.size());
ASSERT_BSONOBJ_EQ(fromjson("{$addFields: {device: '$meta.a', deviceType: '$meta.b'}}"),
serialized[0]);
- ASSERT_BSONOBJ_EQ(unpackSpecObj, serialized[1]);
+ auto extraField = fromjson("{computedMetaProjFields: ['device', 'deviceType']}");
+ ASSERT_BSONOBJ_EQ(BSON("$_internalUnpackBucket" << unpackSpecObj.firstElement().Obj().addField(
+ extraField.firstElement())),
+ serialized[1]);
}
TEST_F(InternalUnpackBucketPushdownProjectionsTest, SplitAddFieldsWithMixedProjectionFields) {
@@ -118,7 +127,10 @@ TEST_F(InternalUnpackBucketPushdownProjectionsTest, SplitAddFieldsWithMixedProje
auto serialized = pipeline->serializeToBson();
ASSERT_EQ(3u, serialized.size());
ASSERT_BSONOBJ_EQ(fromjson("{$addFields: {device: '$meta.a'}}"), serialized[0]);
- ASSERT_BSONOBJ_EQ(unpackSpecObj, serialized[1]);
+ auto extraField = fromjson("{computedMetaProjFields: ['device']}");
+ ASSERT_BSONOBJ_EQ(BSON("$_internalUnpackBucket" << unpackSpecObj.firstElement().Obj().addField(
+ extraField.firstElement())),
+ serialized[1]);
ASSERT_BSONOBJ_EQ(fromjson("{$addFields: {temp: {$add: ['$temperature', '$offset']}}}"),
serialized[2]);
}
@@ -234,6 +246,10 @@ TEST_F(InternalUnpackBucketPushdownProjectionsTest,
auto serialized = pipeline->serializeToBson();
ASSERT_EQ(3u, serialized.size());
ASSERT_BSONOBJ_EQ(fromjson("{$addFields: { device: '$meta.a'}}"), serialized[0]);
+ ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { exclude: [], timeField: 'time', "
+ "metaField: 'myMeta', bucketMaxSpanSeconds: 3600, "
+ "computedMetaProjFields: ['device']}}"),
+ serialized[1]);
ASSERT_BSONOBJ_EQ(fromjson("{$project: {_id: true, device: true}}"), serialized[2]);
}
@@ -255,6 +271,10 @@ TEST_F(InternalUnpackBucketPushdownProjectionsTest,
auto serialized = pipeline->serializeToBson();
ASSERT_EQ(3u, serialized.size());
ASSERT_BSONOBJ_EQ(fromjson("{$addFields: { device: '$meta.a'}}"), serialized[0]);
+ ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { exclude: [], timeField: 'time', "
+ "metaField: 'myMeta', bucketMaxSpanSeconds: 3600, "
+ "computedMetaProjFields: ['device']}}"),
+ serialized[1]);
ASSERT_BSONOBJ_EQ(
fromjson("{$project: {_id: true, x: true, y : {z: true}, device: '$device'}}"),
serialized[2]);
diff --git a/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/sample_reorder_test.cpp b/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/sample_reorder_test.cpp
index b1f1d3d30d4..0b26fce8604 100644
--- a/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/sample_reorder_test.cpp
+++ b/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/sample_reorder_test.cpp
@@ -71,9 +71,10 @@ TEST_F(InternalUnpackBucketSampleReorderTest, SampleThenComputedProject) {
auto serialized = pipeline->serializeToBson();
ASSERT_EQ(3, serialized.size());
- ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { include: ['_id', 'temp'], timeField: "
- "'foo', metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
- serialized[0]);
+ ASSERT_BSONOBJ_EQ(
+ fromjson("{$_internalUnpackBucket: { include: ['_id', 'temp', 'myMeta'], "
+ "timeField: 'foo', metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
+ serialized[0]);
ASSERT_BSONOBJ_EQ(sampleSpec, serialized[1]);
const UnorderedFieldsBSONObjComparator kComparator;
ASSERT_EQ(kComparator.compare(projectSpec, serialized[2]), 0);
@@ -114,9 +115,10 @@ TEST_F(InternalUnpackBucketSampleReorderTest, ComputedProjectThenSample) {
auto serialized = pipeline->serializeToBson();
ASSERT_EQ(3, serialized.size());
- ASSERT_BSONOBJ_EQ(fromjson("{$_internalUnpackBucket: { include: ['_id', 'temp'], timeField: "
- "'foo', metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
- serialized[0]);
+ ASSERT_BSONOBJ_EQ(
+ fromjson("{$_internalUnpackBucket: { include: ['_id', 'temp', 'myMeta'], timeField: "
+ "'foo', metaField: 'myMeta', bucketMaxSpanSeconds: 3600}}"),
+ serialized[0]);
ASSERT_BSONOBJ_EQ(sampleSpec, serialized[1]);
const UnorderedFieldsBSONObjComparator kComparator;
ASSERT_EQ(kComparator.compare(projectSpec, serialized[2]), 0);
diff --git a/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/unpack_bucket_exec_test.cpp b/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/unpack_bucket_exec_test.cpp
index 587ad434e19..126d4d57e48 100644
--- a/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/unpack_bucket_exec_test.cpp
+++ b/src/mongo/db/pipeline/document_source_internal_unpack_bucket_test/unpack_bucket_exec_test.cpp
@@ -824,5 +824,38 @@ TEST_F(InternalUnpackBucketExecTest, ParserRejectsBothIncludeAndExcludeParameter
AssertionException,
5408000);
}
+
+TEST_F(InternalUnpackBucketExecTest, ParserRoundtripsIncludeMeta) {
+ auto bson = fromjson(
+ "{$_internalUnpackBucket: {include: ['steve', 'meta'], timeField: 'time', metaField: "
+ "'meta', bucketMaxSpanSeconds: 3600}}");
+ auto array = std::vector<Value>{};
+ DocumentSourceInternalUnpackBucket::createFromBson(bson.firstElement(), getExpCtx())
+ ->serializeToArray(array);
+ ASSERT_BSONOBJ_EQ(array[0].getDocument().toBson(), bson);
+}
+
+TEST_F(InternalUnpackBucketExecTest, ParserRoundtripsComputedMetaProjFields) {
+ auto bson = fromjson(
+ "{$_internalUnpackBucket: {exclude: [], timeField: 'time', metaField: 'meta', "
+ "bucketMaxSpanSeconds: 3600, computedMetaProjFields: ['a', 'b', 'c']}}");
+ auto array = std::vector<Value>{};
+ DocumentSourceInternalUnpackBucket::createFromBson(bson.firstElement(), getExpCtx())
+ ->serializeToArray(array);
+ ASSERT_BSONOBJ_EQ(array[0].getDocument().toBson(), bson);
+}
+
+TEST_F(InternalUnpackBucketExecTest, ParserRoundtripsComputedMetaProjFieldOverridingMeta) {
+ auto bson = fromjson(
+ "{$_internalUnpackBucket: {exclude: [], timeField: 'time', metaField: 'meta', "
+ "bucketMaxSpanSeconds: 3600, computedMetaProjFields: ['meta']}}");
+ auto unpackBucket =
+ DocumentSourceInternalUnpackBucket::createFromBson(bson.firstElement(), getExpCtx());
+ ASSERT_FALSE(
+ static_cast<DocumentSourceInternalUnpackBucket&>(*unpackBucket).includeMetaField());
+ auto array = std::vector<Value>{};
+ unpackBucket->serializeToArray(array);
+ ASSERT_BSONOBJ_EQ(array[0].getDocument().toBson(), bson);
+}
} // namespace
} // namespace mongo