summaryrefslogtreecommitdiff
path: root/jstests/aggregation
diff options
context:
space:
mode:
authorArun Banala <arun.banala@mongodb.com>2020-06-11 10:47:55 +0100
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-06-26 18:00:55 +0000
commit31499dd163068b6c70a1d2a072aaa9576a628ff0 (patch)
tree4920d80aa94ebf1af16d7f5e2364b63b9d009b4d /jstests/aggregation
parent307c909b4a7bd574b09cd630701a915d2bc982b9 (diff)
downloadmongo-31499dd163068b6c70a1d2a072aaa9576a628ff0.tar.gz
SERVER-48684 Pipeline stage $set fails to set a non-existent dotted field to an object
Diffstat (limited to 'jstests/aggregation')
-rw-r--r--jstests/aggregation/sources/addFields/dotted_paths.js98
1 files changed, 98 insertions, 0 deletions
diff --git a/jstests/aggregation/sources/addFields/dotted_paths.js b/jstests/aggregation/sources/addFields/dotted_paths.js
new file mode 100644
index 00000000000..e8ecdc39d46
--- /dev/null
+++ b/jstests/aggregation/sources/addFields/dotted_paths.js
@@ -0,0 +1,98 @@
+/**
+ * Test the behavior of $addFields in the presence of a dotted field path.
+ */
+(function() {
+const coll = db.add_fields_dotted_paths;
+coll.drop();
+
+let initObj = {
+ _id: 1,
+ arrayField: [1, {subField: [2, {}]}, [1]],
+ objField: {p: {q: 1}, subArr: [1]},
+ otherField: "value"
+};
+assert.commandWorked(coll.insert(initObj));
+
+function assertAddFieldsResult(projection, expectedResults) {
+ assert.eq(coll.aggregate([{$addFields: projection}]).toArray(), [expectedResults]);
+}
+
+// Test that the value gets overwritten when a field exists at a given path.
+initObj["objField"]["subArr"] = "newValue";
+assertAddFieldsResult({"objField.subArr": "newValue"}, initObj);
+assertAddFieldsResult({"objField.subArr": {$literal: "newValue"}}, initObj);
+
+// Test that a new sub-object is created when a field does not exist at a given path. All the
+// existing sibling fields are retained.
+initObj["objField"] = {
+ p: {q: 1},
+ subArr: [1], // Existing fields are retained.
+ newSubPath: {b: "newValue"}
+};
+assertAddFieldsResult({"objField.newSubPath.b": {$literal: "newValue"}}, initObj);
+assertAddFieldsResult({"objField.newSubPath.b": "newValue"}, initObj);
+
+// When the value is a nested object.
+const valueWithNestedObject = {
+ newSubObj: [{p: "newValue"}]
+};
+initObj["objField"]["newSubPath"] = {
+ b: valueWithNestedObject
+};
+assertAddFieldsResult({"objField.newSubPath.b": valueWithNestedObject}, initObj);
+assertAddFieldsResult({"objField.newSubPath.b": {$literal: valueWithNestedObject}}, initObj);
+initObj["objField"] = {
+ p: {q: 1},
+ subArr: [1]
+}; // Reset input object.
+
+// When the top level field doesn"t exist, a new nested object is created based on the given path.
+initObj["newField"] = {
+ newSubPath: {b: "newValue"}
+};
+assertAddFieldsResult({"newField.newSubPath.b": {$literal: "newValue"}}, initObj);
+assertAddFieldsResult({"newField.newSubPath.b": "newValue"}, initObj);
+
+// When the top level field doesn"t exist, a new nested object is created based on the given path
+// and the structure of the object in the value.
+initObj["newField"]["newSubPath"] = {
+ b: valueWithNestedObject
+};
+assertAddFieldsResult({"newField.newSubPath.b": valueWithNestedObject}, initObj);
+assertAddFieldsResult({"newField.newSubPath.b": {$literal: valueWithNestedObject}}, initObj);
+delete initObj["newField"]; // Reset.
+
+// Test when the path encounters an array and the value is a scalar.
+initObj["arrayField"] = {
+ newSubPath: {b: "newValue"}
+};
+let expectedSubObj = {newSubPath: {b: "newValue"}};
+initObj["arrayField"] =
+ [expectedSubObj, Object.assign({subField: [2, {}]}, expectedSubObj), [expectedSubObj]];
+assertAddFieldsResult({"arrayField.newSubPath.b": {$literal: "newValue"}}, initObj);
+assertAddFieldsResult({"arrayField.newSubPath.b": "newValue"}, initObj);
+
+// Test when the path encounters an array and the value is a nested object.
+expectedSubObj = {
+ newSubPath: {b: valueWithNestedObject}
+};
+initObj["arrayField"] =
+ [expectedSubObj, Object.assign({subField: [2, {}]}, expectedSubObj), [expectedSubObj]];
+assertAddFieldsResult({"arrayField.newSubPath.b": valueWithNestedObject}, initObj);
+assertAddFieldsResult({"arrayField.newSubPath.b": {$literal: valueWithNestedObject}}, initObj);
+
+// Test when the path encounters multiple arrays and the value is a nested object.
+expectedSubObj = {
+ subField: {b: valueWithNestedObject}
+};
+initObj["arrayField"] = [
+ expectedSubObj,
+ {
+ subField:
+ [{b: valueWithNestedObject}, {b: valueWithNestedObject}] // Sub-array is also exploded.
+ },
+ [expectedSubObj]
+];
+assertAddFieldsResult({"arrayField.subField.b": valueWithNestedObject}, initObj);
+assertAddFieldsResult({"arrayField.subField.b": {$literal: valueWithNestedObject}}, initObj);
+})();