diff --git a/src/change_stream.ts b/src/change_stream.ts index 93be71047f..d9b6adefa9 100644 --- a/src/change_stream.ts +++ b/src/change_stream.ts @@ -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 */ collectionUUID: Binary; } @@ -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; } @@ -496,6 +496,25 @@ export interface UpdateDescription { /** 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 */ diff --git a/test/spec/change-streams/unified/change-streams-disambiguatedPaths.json b/test/spec/change-streams/unified/change-streams-disambiguatedPaths.json new file mode 100644 index 0000000000..9a639801ee --- /dev/null +++ b/test/spec/change-streams/unified/change-streams-disambiguatedPaths.json @@ -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" + ] + } + } + } + } + ] + } + ] +} diff --git a/test/spec/change-streams/unified/change-streams-disambiguatedPaths.yml b/test/spec/change-streams/unified/change-streams-disambiguatedPaths.yml new file mode 100644 index 0000000000..674c876b02 --- /dev/null +++ b/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'] } diff --git a/tsdoc.json b/tsdoc.json index 81ce5c1da8..0d65244184 100644 --- a/tsdoc.json +++ b/tsdoc.json @@ -9,6 +9,10 @@ "syntaxKind": "block", "tagName": "@since" }, + { + "syntaxKind": "block", + "tagName": "@sinceServerVersion" + }, { "syntaxKind": "block", "tagName": "@category"