summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Zolnierz <nicholas.zolnierz@mongodb.com>2022-01-19 15:21:32 -0500
committerNicholas Zolnierz <nicholas.zolnierz@mongodb.com>2022-01-19 15:21:36 -0500
commit76d67ea903cdad9cb574f197ba04e63b0747a3ca (patch)
tree976097e8ca7166e0b1085e40502a8072ee67ac36
parentb3a66de85077da1e8304bb3e86736f1f061c5419 (diff)
downloadmongo-server-62322-setWindowFields-empty-obj.tar.gz
SERVER-62322 Allow an empty object to be projected in $setWindowFieldsserver-62322-setWindowFields-empty-obj
-rw-r--r--jstests/aggregation/sources/setWindowFields/parse.js13
-rw-r--r--src/mongo/db/pipeline/document_source_set_window_fields.cpp7
2 files changed, 16 insertions, 4 deletions
diff --git a/jstests/aggregation/sources/setWindowFields/parse.js b/jstests/aggregation/sources/setWindowFields/parse.js
index 63b92e952e0..b766a76d8ae 100644
--- a/jstests/aggregation/sources/setWindowFields/parse.js
+++ b/jstests/aggregation/sources/setWindowFields/parse.js
@@ -213,8 +213,7 @@ assert.commandWorked(run({
}));
// Not every accumulator is automatically a window function.
-
-var err = assert.commandFailedWithCode(run({$setWindowFields: {output: {a: {b: {$sum: "$a"}}}}}),
+let err = assert.commandFailedWithCode(run({$setWindowFields: {output: {a: {b: {$sum: "$a"}}}}}),
ErrorCodes.FailedToParse);
assert.includes(err.errmsg, 'Expected a $-prefixed window function, b');
@@ -250,4 +249,14 @@ err = assert.commandFailedWithCode(
}),
ErrorCodes.FailedToParse);
assert.includes(err.errmsg, 'Unrecognized window function, $summ');
+
+// Test that an empty object is a valid projected field.
+assert.commandWorked(coll.insert({}));
+assert.commandWorked(run({$setWindowFields: {output: {v: {$max: {mergeObjects: {}}}}}}));
+
+// However conflicting field paths is always an error.
+err = assert.commandFailedWithCode(
+ run({$setWindowFields: {output: {a: {$sum: 1}, 'a.b': {$sum: 1}}}}), 40176);
+assert.includes(err.errmsg, 'specification contains two conflicting paths');
+
})();
diff --git a/src/mongo/db/pipeline/document_source_set_window_fields.cpp b/src/mongo/db/pipeline/document_source_set_window_fields.cpp
index 87cd3ad0267..09e27df140a 100644
--- a/src/mongo/db/pipeline/document_source_set_window_fields.cpp
+++ b/src/mongo/db/pipeline/document_source_set_window_fields.cpp
@@ -461,10 +461,12 @@ DocumentSource::GetNextResult DocumentSourceInternalSetWindowFields::doGetNext()
MutableDocument addFieldsSpec;
for (auto&& [fieldName, function] : _executableOutputs) {
try {
+ // Wrap the projected value in a $literal since there are limitations on a user-facing
+ // $addFields that we don't want to enforce here (e.g. empty object).
+ addFieldsSpec.addField(fieldName, Value(DOC("$literal" << function->getNext())));
+ } catch (const DBException&) {
// If we hit a uassert while evaluating expressions on user data, delete the temporary
// table before aborting the operation.
- addFieldsSpec.addField(fieldName, function->getNext());
- } catch (const DBException&) {
_iterator.finalize();
throw;
}
@@ -506,6 +508,7 @@ DocumentSource::GetNextResult DocumentSourceInternalSetWindowFields::doGetNext()
_iterator.finalize();
break;
}
+
auto projExec = projection_executor::AddFieldsProjectionExecutor::create(
pExpCtx, addFieldsSpec.freeze().toBson());