mirror of https://github.com/mongodb/mongo
200 lines
7.6 KiB
JavaScript
200 lines
7.6 KiB
JavaScript
/**
|
|
* Test change stream 'updateDescription' with 'showExpandedEvents'.
|
|
*/
|
|
|
|
import {assertDropAndRecreateCollection} from "jstests/libs/collection_drop_recreate.js";
|
|
import {ChangeStreamTest} from "jstests/libs/query/change_stream_util.js";
|
|
|
|
// Drop and recreate the collections to be used in this set of tests.
|
|
assertDropAndRecreateCollection(db, "coll");
|
|
|
|
const cst = new ChangeStreamTest(db);
|
|
|
|
const kLargeStr = '*'.repeat(128);
|
|
assert.commandWorked(db.coll.insert({
|
|
_id: 100,
|
|
"topLevelArray": [{subArray: [0, [0, [{bottomArray: [1, 2, kLargeStr]}]], 2, 3, kLargeStr]}],
|
|
"arrayForReplacement": [0, 1, 2, 3],
|
|
"arrayForResize": [kLargeStr, 1],
|
|
obj: {
|
|
'sub.obj': {'d.o.t.t.e.d.a.r.r.a.y..': [[{a: {'b.c': 1, field: kLargeStr}}, "truncated"]]}
|
|
},
|
|
'd.o.t.t.e.d.o.b.j.': {'sub.obj': {'b.c': 2}},
|
|
'objectWithNumericField': {'0': {'1': 'numeric', field: kLargeStr}},
|
|
"arrayWithNumericField": [[{'0': "numeric", a: {'b.c': 1}, field: kLargeStr}]],
|
|
"arrayWithDotted.AndNumericFields": [[{'0': [{'1.2': {'a.b': null, c: kLargeStr}}]}]],
|
|
}));
|
|
|
|
const changeStreamCursor = cst.startWatchingChanges(
|
|
{pipeline: [{$changeStream: {showExpandedEvents: true}}], collection: db.coll});
|
|
|
|
// Test that a path which only contains non-dotted fields and array indices is not reported under
|
|
// 'disambiguatedPaths'.
|
|
assert.commandWorked(db.coll.update({_id: 100}, {
|
|
$set: {"a": 2, "topLevelArray.0.subArray.1.1.0.bottomArray.2": 3, "arrayForReplacement": [0]}
|
|
}));
|
|
|
|
let expected = {
|
|
documentKey: {_id: 100},
|
|
ns: {db: "test", coll: "coll"},
|
|
operationType: "update",
|
|
updateDescription: {
|
|
updatedFields:
|
|
{"arrayForReplacement": [0], "a": 2, "topLevelArray.0.subArray.1.1.0.bottomArray.2": 3},
|
|
removedFields: [],
|
|
truncatedArrays: [],
|
|
disambiguatedPaths: {}
|
|
},
|
|
};
|
|
cst.assertNextChangesEqual({cursor: changeStreamCursor, expectedChanges: [expected]});
|
|
|
|
// Tests that an update modifying a non-array numeric field name is reported as a string rather than
|
|
// as an integer under 'disambiguatedPaths'. Array indexes are reported as integers.
|
|
assert.commandWorked(
|
|
db.coll.update({_id: 100}, {$set: {"arrayWithNumericField.0.0.1": {"b.c": 1}}}));
|
|
expected = {
|
|
documentKey: {_id: 100},
|
|
ns: {db: "test", coll: "coll"},
|
|
operationType: "update",
|
|
updateDescription: {
|
|
updatedFields: {"arrayWithNumericField.0.0.1": {"b.c": 1}},
|
|
removedFields: [],
|
|
truncatedArrays: [],
|
|
disambiguatedPaths: {"arrayWithNumericField.0.0.1": ["arrayWithNumericField", 0, 0, "1"]}
|
|
},
|
|
};
|
|
cst.assertNextChangesEqual({cursor: changeStreamCursor, expectedChanges: [expected]});
|
|
|
|
// Tests that an update modifying a non-array numeric field name is reported when no array indices
|
|
// or dotted fields are present.
|
|
assert.commandWorked(db.coll.update({_id: 100}, {$set: {"objectWithNumericField.0.1": "updated"}}));
|
|
expected = {
|
|
documentKey: {_id: 100},
|
|
ns: {db: "test", coll: "coll"},
|
|
operationType: "update",
|
|
updateDescription: {
|
|
updatedFields: {"objectWithNumericField.0.1": "updated"},
|
|
removedFields: [],
|
|
truncatedArrays: [],
|
|
disambiguatedPaths: {"objectWithNumericField.0.1": ["objectWithNumericField", "0", "1"]}
|
|
},
|
|
};
|
|
cst.assertNextChangesEqual({cursor: changeStreamCursor, expectedChanges: [expected]});
|
|
|
|
// Tests that an update with $unset array does not report the array under 'disambiguatedPaths'.
|
|
assert.commandWorked(db.coll.update({_id: 100}, [{$unset: ["arrayForReplacement"]}]));
|
|
expected = {
|
|
documentKey: {_id: 100},
|
|
ns: {db: "test", coll: "coll"},
|
|
operationType: "update",
|
|
updateDescription: {
|
|
updatedFields: {},
|
|
removedFields: ["arrayForReplacement"],
|
|
truncatedArrays: [],
|
|
disambiguatedPaths: {}
|
|
},
|
|
};
|
|
cst.assertNextChangesEqual({cursor: changeStreamCursor, expectedChanges: [expected]});
|
|
|
|
// Tests that an update with 'truncatedArrays' does not report the array under 'disambiguatedPaths'.
|
|
assert.commandWorked(db.coll.update({_id: 100}, [
|
|
{$replaceWith: {$setField: {field: "arrayForResize", input: '$$ROOT', value: [kLargeStr]}}},
|
|
]));
|
|
expected = {
|
|
documentKey: {_id: 100},
|
|
ns: {db: "test", coll: "coll"},
|
|
operationType: "update",
|
|
updateDescription: {
|
|
updatedFields: {},
|
|
removedFields: [],
|
|
truncatedArrays: [{field: "arrayForResize", newSize: 1}],
|
|
disambiguatedPaths: {}
|
|
},
|
|
};
|
|
cst.assertNextChangesEqual({cursor: changeStreamCursor, expectedChanges: [expected]});
|
|
|
|
// Verify that top-level dotted fields are reported under 'disambiguatedPaths'.
|
|
assert.commandWorked(db.coll.update({_id: 100}, [
|
|
{
|
|
$replaceWith:
|
|
{$setField: {field: "d.o.t.t.e.d.o.b.j.", input: '$$ROOT', value: {'subObj': 1}}}
|
|
},
|
|
{$replaceWith: {$setField: {field: "new.Field.", input: '$$ROOT', value: 1}}}
|
|
]));
|
|
expected = {
|
|
documentKey: {_id: 100},
|
|
ns: {db: "test", coll: "coll"},
|
|
operationType: "update",
|
|
updateDescription: {
|
|
updatedFields: {"d.o.t.t.e.d.o.b.j.": {subObj: 1}, "new.Field.": 1},
|
|
removedFields: [],
|
|
truncatedArrays: [],
|
|
disambiguatedPaths:
|
|
{"d.o.t.t.e.d.o.b.j.": ["d.o.t.t.e.d.o.b.j."], "new.Field.": ["new.Field."]}
|
|
},
|
|
};
|
|
cst.assertNextChangesEqual({cursor: changeStreamCursor, expectedChanges: [expected]});
|
|
|
|
// Test that a combination of dotted fields and array indices are reported in 'disambiguatedPaths'.
|
|
assert.commandWorked(db.coll.update(
|
|
{_id: 100}, [{
|
|
$set: {
|
|
obj: {
|
|
$setField: {
|
|
field: "sub.obj",
|
|
input: '$obj',
|
|
value: {
|
|
$literal: {'d.o.t.t.e.d.a.r.r.a.y..': [[{a: {'b.c': 2, field: kLargeStr}}]]}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}]));
|
|
expected = {
|
|
documentKey: {_id: 100},
|
|
ns: {db: "test", coll: "coll"},
|
|
operationType: "update",
|
|
updateDescription: {
|
|
updatedFields: {"obj.sub.obj.d.o.t.t.e.d.a.r.r.a.y...0.0.a.b.c": 2},
|
|
removedFields: [],
|
|
truncatedArrays: [{field: "obj.sub.obj.d.o.t.t.e.d.a.r.r.a.y...0", newSize: 1}],
|
|
disambiguatedPaths: {
|
|
"obj.sub.obj.d.o.t.t.e.d.a.r.r.a.y...0":
|
|
["obj", "sub.obj", "d.o.t.t.e.d.a.r.r.a.y..", 0],
|
|
"obj.sub.obj.d.o.t.t.e.d.a.r.r.a.y...0.0.a.b.c":
|
|
["obj", "sub.obj", "d.o.t.t.e.d.a.r.r.a.y..", 0, 0, "a", "b.c"],
|
|
}
|
|
},
|
|
};
|
|
cst.assertNextChangesEqual({cursor: changeStreamCursor, expectedChanges: [expected]});
|
|
|
|
// Test that an update which modifies a path containing dotted, numeric and array index fields
|
|
// distinguishes all three in 'disambiguatedPaths'.
|
|
assert.commandWorked(
|
|
db.coll.update({_id: 100}, [{
|
|
$replaceWith: {
|
|
$setField: {
|
|
field: "arrayWithDotted.AndNumericFields",
|
|
input: '$$ROOT',
|
|
value: {$literal: [[{'0': [{'1.2': {'a.b': true, c: kLargeStr}}]}]]}
|
|
}
|
|
}
|
|
}]));
|
|
expected = {
|
|
documentKey: {_id: 100},
|
|
ns: {db: "test", coll: "coll"},
|
|
operationType: "update",
|
|
updateDescription: {
|
|
updatedFields: {"arrayWithDotted.AndNumericFields.0.0.0.0.1.2.a.b": true},
|
|
removedFields: [],
|
|
truncatedArrays: [],
|
|
disambiguatedPaths: {
|
|
"arrayWithDotted.AndNumericFields.0.0.0.0.1.2.a.b":
|
|
["arrayWithDotted.AndNumericFields", 0, 0, "0", 0, "1.2", "a.b"]
|
|
}
|
|
},
|
|
};
|
|
cst.assertNextChangesEqual({cursor: changeStreamCursor, expectedChanges: [expected]});
|
|
|
|
cst.cleanUp();
|