Skip to content

Commit 846365a

Browse files
feat(NODE-4484): add experimental support for disambiguatedPaths in change stream documents (mongodb#3365)
1 parent 2e47102 commit 846365a

File tree

4 files changed

+378
-2
lines changed

4 files changed

+378
-2
lines changed

src/change_stream.ts

+21-2
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ export interface ChangeStreamDocumentCollectionUUID {
210210
* **NOTE:** collectionUUID will be converted to a NodeJS Buffer if the promoteBuffers
211211
* flag is enabled.
212212
*
213-
* @since 6.1.0
213+
* @sinceServerVersion 6.1.0
214214
*/
215215
collectionUUID: Binary;
216216
}
@@ -222,7 +222,7 @@ export interface ChangeStreamDocumentOperationDescription {
222222
*
223223
* Only present when the `showExpandedEvents` flag is enabled.
224224
*
225-
* @since 6.1.0
225+
* @sinceServerVersion 6.1.0
226226
*/
227227
operationDescription?: Document;
228228
}
@@ -496,6 +496,25 @@ export interface UpdateDescription<TSchema extends Document = Document> {
496496
/** The number of elements in the truncated array. */
497497
newSize: number;
498498
}>;
499+
500+
/**
501+
* A document containing additional information about any ambiguous update paths from the update event. The document
502+
* maps the full ambiguous update path to an array containing the actual resolved components of the path. For example,
503+
* given a document shaped like `{ a: { '0': 0 } }`, and an update of `{ $inc: 'a.0' }`, disambiguated paths would look like
504+
* the following:
505+
*
506+
* ```
507+
* {
508+
* 'a.0': ['a', '0']
509+
* }
510+
* ```
511+
*
512+
* This field is only present when there are ambiguous paths that are updated as a part of the update event and `showExpandedEvents`
513+
* is enabled for the change stream.
514+
* @sinceServerVersion 6.1.0
515+
* @experimental
516+
*/
517+
disambiguatedPaths?: Document;
499518
}
500519

501520
/** @public */
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
{
2+
"description": "disambiguatedPaths",
3+
"schemaVersion": "1.3",
4+
"createEntities": [
5+
{
6+
"client": {
7+
"id": "client0",
8+
"useMultipleMongoses": false
9+
}
10+
},
11+
{
12+
"database": {
13+
"id": "database0",
14+
"client": "client0",
15+
"databaseName": "database0"
16+
}
17+
},
18+
{
19+
"collection": {
20+
"id": "collection0",
21+
"database": "database0",
22+
"collectionName": "collection0"
23+
}
24+
}
25+
],
26+
"runOnRequirements": [
27+
{
28+
"minServerVersion": "6.1.0",
29+
"topologies": [
30+
"replicaset",
31+
"sharded-replicaset",
32+
"load-balanced",
33+
"sharded"
34+
]
35+
}
36+
],
37+
"initialData": [
38+
{
39+
"collectionName": "collection0",
40+
"databaseName": "database0",
41+
"documents": []
42+
}
43+
],
44+
"tests": [
45+
{
46+
"description": "disambiguatedPaths is not present when showExpandedEvents is false/unset",
47+
"operations": [
48+
{
49+
"name": "insertOne",
50+
"object": "collection0",
51+
"arguments": {
52+
"document": {
53+
"_id": 1,
54+
"a": {
55+
"1": 1
56+
}
57+
}
58+
}
59+
},
60+
{
61+
"name": "createChangeStream",
62+
"object": "collection0",
63+
"arguments": {
64+
"pipeline": []
65+
},
66+
"saveResultAsEntity": "changeStream0"
67+
},
68+
{
69+
"name": "updateOne",
70+
"object": "collection0",
71+
"arguments": {
72+
"filter": {
73+
"_id": 1
74+
},
75+
"update": {
76+
"$set": {
77+
"a.1": 2
78+
}
79+
}
80+
}
81+
},
82+
{
83+
"name": "iterateUntilDocumentOrError",
84+
"object": "changeStream0",
85+
"expectResult": {
86+
"operationType": "update",
87+
"ns": {
88+
"db": "database0",
89+
"coll": "collection0"
90+
},
91+
"updateDescription": {
92+
"updatedFields": {
93+
"$$exists": true
94+
},
95+
"removedFields": {
96+
"$$exists": true
97+
},
98+
"truncatedArrays": {
99+
"$$exists": true
100+
},
101+
"disambiguatedPaths": {
102+
"$$exists": false
103+
}
104+
}
105+
}
106+
}
107+
]
108+
},
109+
{
110+
"description": "disambiguatedPaths is present on updateDescription when an ambiguous path is present",
111+
"operations": [
112+
{
113+
"name": "insertOne",
114+
"object": "collection0",
115+
"arguments": {
116+
"document": {
117+
"_id": 1,
118+
"a": {
119+
"1": 1
120+
}
121+
}
122+
}
123+
},
124+
{
125+
"name": "createChangeStream",
126+
"object": "collection0",
127+
"arguments": {
128+
"pipeline": [],
129+
"showExpandedEvents": true
130+
},
131+
"saveResultAsEntity": "changeStream0"
132+
},
133+
{
134+
"name": "updateOne",
135+
"object": "collection0",
136+
"arguments": {
137+
"filter": {
138+
"_id": 1
139+
},
140+
"update": {
141+
"$set": {
142+
"a.1": 2
143+
}
144+
}
145+
}
146+
},
147+
{
148+
"name": "iterateUntilDocumentOrError",
149+
"object": "changeStream0",
150+
"expectResult": {
151+
"operationType": "update",
152+
"ns": {
153+
"db": "database0",
154+
"coll": "collection0"
155+
},
156+
"updateDescription": {
157+
"updatedFields": {
158+
"$$exists": true
159+
},
160+
"removedFields": {
161+
"$$exists": true
162+
},
163+
"truncatedArrays": {
164+
"$$exists": true
165+
},
166+
"disambiguatedPaths": {
167+
"a.1": [
168+
"a",
169+
"1"
170+
]
171+
}
172+
}
173+
}
174+
}
175+
]
176+
},
177+
{
178+
"description": "disambiguatedPaths returns array indices as integers",
179+
"operations": [
180+
{
181+
"name": "insertOne",
182+
"object": "collection0",
183+
"arguments": {
184+
"document": {
185+
"_id": 1,
186+
"a": [
187+
{
188+
"1": 1
189+
}
190+
]
191+
}
192+
}
193+
},
194+
{
195+
"name": "createChangeStream",
196+
"object": "collection0",
197+
"arguments": {
198+
"pipeline": [],
199+
"showExpandedEvents": true
200+
},
201+
"saveResultAsEntity": "changeStream0"
202+
},
203+
{
204+
"name": "updateOne",
205+
"object": "collection0",
206+
"arguments": {
207+
"filter": {
208+
"_id": 1
209+
},
210+
"update": {
211+
"$set": {
212+
"a.0.1": 2
213+
}
214+
}
215+
}
216+
},
217+
{
218+
"name": "iterateUntilDocumentOrError",
219+
"object": "changeStream0",
220+
"expectResult": {
221+
"operationType": "update",
222+
"ns": {
223+
"db": "database0",
224+
"coll": "collection0"
225+
},
226+
"updateDescription": {
227+
"updatedFields": {
228+
"$$exists": true
229+
},
230+
"removedFields": {
231+
"$$exists": true
232+
},
233+
"truncatedArrays": {
234+
"$$exists": true
235+
},
236+
"disambiguatedPaths": {
237+
"a.0.1": [
238+
"a",
239+
{
240+
"$$type": "int"
241+
},
242+
"1"
243+
]
244+
}
245+
}
246+
}
247+
}
248+
]
249+
}
250+
]
251+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
description: "disambiguatedPaths"
2+
schemaVersion: "1.3"
3+
createEntities:
4+
- client:
5+
id: &client0 client0
6+
useMultipleMongoses: false
7+
- database:
8+
id: &database0 database0
9+
client: *client0
10+
databaseName: *database0
11+
- collection:
12+
id: &collection0 collection0
13+
database: *database0
14+
collectionName: *collection0
15+
16+
runOnRequirements:
17+
- minServerVersion: "6.1.0"
18+
topologies: [ replicaset, sharded-replicaset, load-balanced, sharded ]
19+
20+
initialData:
21+
- collectionName: *collection0
22+
databaseName: *database0
23+
documents: []
24+
25+
tests:
26+
- description: "disambiguatedPaths is not present when showExpandedEvents is false/unset"
27+
operations:
28+
- name: insertOne
29+
object: *collection0
30+
arguments:
31+
document: { _id: 1, 'a': { '1': 1 } }
32+
- name: createChangeStream
33+
object: *collection0
34+
arguments: { pipeline: [] }
35+
saveResultAsEntity: &changeStream0 changeStream0
36+
- name: updateOne
37+
object: *collection0
38+
arguments:
39+
filter: { _id: 1 }
40+
update: { $set: { 'a.1': 2 } }
41+
- name: iterateUntilDocumentOrError
42+
object: *changeStream0
43+
expectResult:
44+
operationType: "update"
45+
ns: { db: *database0, coll: *collection0 }
46+
updateDescription:
47+
updatedFields: { $$exists: true }
48+
removedFields: { $$exists: true }
49+
truncatedArrays: { $$exists: true }
50+
disambiguatedPaths: { $$exists: false }
51+
52+
- description: "disambiguatedPaths is present on updateDescription when an ambiguous path is present"
53+
operations:
54+
- name: insertOne
55+
object: *collection0
56+
arguments:
57+
document: { _id: 1, 'a': { '1': 1 } }
58+
- name: createChangeStream
59+
object: *collection0
60+
arguments: { pipeline: [], showExpandedEvents: true }
61+
saveResultAsEntity: &changeStream0 changeStream0
62+
- name: updateOne
63+
object: *collection0
64+
arguments:
65+
filter: { _id: 1 }
66+
update: { $set: { 'a.1': 2 } }
67+
- name: iterateUntilDocumentOrError
68+
object: *changeStream0
69+
expectResult:
70+
operationType: "update"
71+
ns: { db: *database0, coll: *collection0 }
72+
updateDescription:
73+
updatedFields: { $$exists: true }
74+
removedFields: { $$exists: true }
75+
truncatedArrays: { $$exists: true }
76+
disambiguatedPaths: { 'a.1': ['a', '1'] }
77+
78+
- description: "disambiguatedPaths returns array indices as integers"
79+
operations:
80+
- name: insertOne
81+
object: *collection0
82+
arguments:
83+
document: { _id: 1, 'a': [{'1': 1 }] }
84+
- name: createChangeStream
85+
object: *collection0
86+
arguments: { pipeline: [], showExpandedEvents: true }
87+
saveResultAsEntity: &changeStream0 changeStream0
88+
- name: updateOne
89+
object: *collection0
90+
arguments:
91+
filter: { _id: 1 }
92+
update: { $set: { 'a.0.1': 2 } }
93+
- name: iterateUntilDocumentOrError
94+
object: *changeStream0
95+
expectResult:
96+
operationType: "update"
97+
ns: { db: *database0, coll: *collection0 }
98+
updateDescription:
99+
updatedFields: { $$exists: true }
100+
removedFields: { $$exists: true }
101+
truncatedArrays: { $$exists: true }
102+
disambiguatedPaths: { 'a.0.1': ['a', { $$type: 'int' }, '1'] }

0 commit comments

Comments
 (0)