94 lines
3.7 KiB
JavaScript
94 lines
3.7 KiB
JavaScript
/**
|
|
* Test the behavior of $addFields in the presence of a dotted field path.
|
|
*/
|
|
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);
|