summaryrefslogtreecommitdiff
path: root/jstests/aggregation/sources/addFields/dotted_paths.js
blob: e8ecdc39d46edd04164c469951ac4ba9ca1d582e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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);
})();