Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(NODE-4484): add experimental support for disambiguatedPaths in change stream documents #3365

Merged
merged 5 commits into from Aug 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
23 changes: 21 additions & 2 deletions src/change_stream.ts
Expand Up @@ -210,7 +210,7 @@ export interface ChangeStreamDocumentCollectionUUID {
* **NOTE:** collectionUUID will be converted to a NodeJS Buffer if the promoteBuffers
* flag is enabled.
*
* @since 6.1.0
* @sinceServerVersion 6.1.0
durran marked this conversation as resolved.
Show resolved Hide resolved
*/
collectionUUID: Binary;
}
Expand All @@ -222,7 +222,7 @@ export interface ChangeStreamDocumentOperationDescription {
*
* Only present when the `showExpandedEvents` flag is enabled.
*
* @since 6.1.0
* @sinceServerVersion 6.1.0
*/
operationDescription?: Document;
}
Expand Down Expand Up @@ -496,6 +496,25 @@ export interface UpdateDescription<TSchema extends Document = Document> {
/** The number of elements in the truncated array. */
newSize: number;
}>;

/**
* A document containing additional information about any ambiguous update paths from the update event. The document
* maps the full ambiguous update path to an array containing the actual resolved components of the path. For example,
* given a document shaped like `{ a: { '0': 0 } }`, and an update of `{ $inc: 'a.0' }`, disambiguated paths would look like
* the following:
*
* ```
* {
* 'a.0': ['a', '0']
* }
* ```
*
* This field is only present when there are ambiguous paths that are updated as a part of the update event and `showExpandedEvents`
* is enabled for the change stream.
* @sinceServerVersion 6.1.0
* @experimental
*/
disambiguatedPaths?: Document;
}

/** @public */
Expand Down
@@ -0,0 +1,251 @@
{
"description": "disambiguatedPaths",
"schemaVersion": "1.3",
"createEntities": [
{
"client": {
"id": "client0",
"useMultipleMongoses": false
}
},
{
"database": {
"id": "database0",
"client": "client0",
"databaseName": "database0"
}
},
{
"collection": {
"id": "collection0",
"database": "database0",
"collectionName": "collection0"
}
}
],
"runOnRequirements": [
{
"minServerVersion": "6.1.0",
"topologies": [
"replicaset",
"sharded-replicaset",
"load-balanced",
"sharded"
]
}
],
"initialData": [
{
"collectionName": "collection0",
"databaseName": "database0",
"documents": []
}
],
"tests": [
{
"description": "disambiguatedPaths is not present when showExpandedEvents is false/unset",
"operations": [
{
"name": "insertOne",
"object": "collection0",
"arguments": {
"document": {
"_id": 1,
"a": {
"1": 1
}
}
}
},
{
"name": "createChangeStream",
"object": "collection0",
"arguments": {
"pipeline": []
},
"saveResultAsEntity": "changeStream0"
},
{
"name": "updateOne",
"object": "collection0",
"arguments": {
"filter": {
"_id": 1
},
"update": {
"$set": {
"a.1": 2
}
}
}
},
{
"name": "iterateUntilDocumentOrError",
"object": "changeStream0",
"expectResult": {
"operationType": "update",
"ns": {
"db": "database0",
"coll": "collection0"
},
"updateDescription": {
"updatedFields": {
"$$exists": true
},
"removedFields": {
"$$exists": true
},
"truncatedArrays": {
"$$exists": true
},
"disambiguatedPaths": {
"$$exists": false
}
}
}
}
]
},
{
"description": "disambiguatedPaths is present on updateDescription when an ambiguous path is present",
"operations": [
{
"name": "insertOne",
"object": "collection0",
"arguments": {
"document": {
"_id": 1,
"a": {
"1": 1
}
}
}
},
{
"name": "createChangeStream",
"object": "collection0",
"arguments": {
"pipeline": [],
"showExpandedEvents": true
},
"saveResultAsEntity": "changeStream0"
},
{
"name": "updateOne",
"object": "collection0",
"arguments": {
"filter": {
"_id": 1
},
"update": {
"$set": {
"a.1": 2
}
}
}
},
{
"name": "iterateUntilDocumentOrError",
"object": "changeStream0",
"expectResult": {
"operationType": "update",
"ns": {
"db": "database0",
"coll": "collection0"
},
"updateDescription": {
"updatedFields": {
"$$exists": true
},
"removedFields": {
"$$exists": true
},
"truncatedArrays": {
"$$exists": true
},
"disambiguatedPaths": {
"a.1": [
"a",
"1"
]
}
}
}
}
]
},
{
"description": "disambiguatedPaths returns array indices as integers",
"operations": [
{
"name": "insertOne",
"object": "collection0",
"arguments": {
"document": {
"_id": 1,
"a": [
{
"1": 1
}
]
}
}
},
{
"name": "createChangeStream",
"object": "collection0",
"arguments": {
"pipeline": [],
"showExpandedEvents": true
},
"saveResultAsEntity": "changeStream0"
},
{
"name": "updateOne",
"object": "collection0",
"arguments": {
"filter": {
"_id": 1
},
"update": {
"$set": {
"a.0.1": 2
}
}
}
},
{
"name": "iterateUntilDocumentOrError",
"object": "changeStream0",
"expectResult": {
"operationType": "update",
"ns": {
"db": "database0",
"coll": "collection0"
},
"updateDescription": {
"updatedFields": {
"$$exists": true
},
"removedFields": {
"$$exists": true
},
"truncatedArrays": {
"$$exists": true
},
"disambiguatedPaths": {
"a.0.1": [
"a",
{
"$$type": "int"
},
"1"
]
}
}
}
}
]
}
]
}
102 changes: 102 additions & 0 deletions test/spec/change-streams/unified/change-streams-disambiguatedPaths.yml
@@ -0,0 +1,102 @@
description: "disambiguatedPaths"
schemaVersion: "1.3"
createEntities:
- client:
id: &client0 client0
useMultipleMongoses: false
- database:
id: &database0 database0
client: *client0
databaseName: *database0
- collection:
id: &collection0 collection0
database: *database0
collectionName: *collection0

runOnRequirements:
- minServerVersion: "6.1.0"
topologies: [ replicaset, sharded-replicaset, load-balanced, sharded ]

initialData:
- collectionName: *collection0
databaseName: *database0
documents: []

tests:
- description: "disambiguatedPaths is not present when showExpandedEvents is false/unset"
operations:
- name: insertOne
object: *collection0
arguments:
document: { _id: 1, 'a': { '1': 1 } }
- name: createChangeStream
object: *collection0
arguments: { pipeline: [] }
saveResultAsEntity: &changeStream0 changeStream0
- name: updateOne
object: *collection0
arguments:
filter: { _id: 1 }
update: { $set: { 'a.1': 2 } }
- name: iterateUntilDocumentOrError
object: *changeStream0
expectResult:
operationType: "update"
ns: { db: *database0, coll: *collection0 }
updateDescription:
updatedFields: { $$exists: true }
removedFields: { $$exists: true }
truncatedArrays: { $$exists: true }
disambiguatedPaths: { $$exists: false }

- description: "disambiguatedPaths is present on updateDescription when an ambiguous path is present"
operations:
- name: insertOne
object: *collection0
arguments:
document: { _id: 1, 'a': { '1': 1 } }
- name: createChangeStream
object: *collection0
arguments: { pipeline: [], showExpandedEvents: true }
saveResultAsEntity: &changeStream0 changeStream0
- name: updateOne
object: *collection0
arguments:
filter: { _id: 1 }
update: { $set: { 'a.1': 2 } }
- name: iterateUntilDocumentOrError
object: *changeStream0
expectResult:
operationType: "update"
ns: { db: *database0, coll: *collection0 }
updateDescription:
updatedFields: { $$exists: true }
removedFields: { $$exists: true }
truncatedArrays: { $$exists: true }
disambiguatedPaths: { 'a.1': ['a', '1'] }

- description: "disambiguatedPaths returns array indices as integers"
operations:
- name: insertOne
object: *collection0
arguments:
document: { _id: 1, 'a': [{'1': 1 }] }
- name: createChangeStream
object: *collection0
arguments: { pipeline: [], showExpandedEvents: true }
saveResultAsEntity: &changeStream0 changeStream0
- name: updateOne
object: *collection0
arguments:
filter: { _id: 1 }
update: { $set: { 'a.0.1': 2 } }
- name: iterateUntilDocumentOrError
object: *changeStream0
expectResult:
operationType: "update"
ns: { db: *database0, coll: *collection0 }
updateDescription:
updatedFields: { $$exists: true }
removedFields: { $$exists: true }
truncatedArrays: { $$exists: true }
disambiguatedPaths: { 'a.0.1': ['a', { $$type: 'int' }, '1'] }