diff options
author | Arun Banala <arun.banala@mongodb.com> | 2020-06-11 10:47:55 +0100 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-06-26 18:00:55 +0000 |
commit | 31499dd163068b6c70a1d2a072aaa9576a628ff0 (patch) | |
tree | 4920d80aa94ebf1af16d7f5e2364b63b9d009b4d /jstests/aggregation | |
parent | 307c909b4a7bd574b09cd630701a915d2bc982b9 (diff) | |
download | mongo-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.js | 98 |
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); +})(); |