Docs Menu
Docs Home
/

MongoDB Change Streams

Change streams allow applications to access real-time data changes without the prior complexity and risk of manually tailing the oplog. Applications can use change streams to subscribe to all data changes on a single collection, a database, or an entire deployment, and immediately react to them. Because change streams use the aggregation framework, applications can also filter for specific changes or transform the notifications at will.

Note

Change streams are restricted to database events. Atlas Stream Processing has extended functionality, including managing multiple data event types and processing streams of complex data using the same query API as Atlas databases. For more information, see Atlas Stream Processing.

Starting in MongoDB 5.1, change streams are optimized, providing more efficient resource utilization and faster execution of some aggregation pipeline stages.

Change streams are available for replica sets and sharded clusters:

Note

Time series collections do not support change streams because time series collections use an optimized storage format instead of tracking changes at the document level. You cannot use time series collections as a source for Atlas Stream Processing.

Tip

See Time Series Collection Limitations for more information.

Change streams are included in Stable API V1. However, the showExpandedEvents option is not included in Stable API V1.

Connections for a change stream can either use DNS seed lists with the +srv connection option or by listing the servers individually in the connection string.

If the driver loses the connection to a change stream or the connection goes down, it attempts to reestablish a connection to the change stream through another node in the cluster that has a matching read preference. If the driver cannot find a node with the correct read preference, it throws an exception.

For more information, see Connection String URI Format.

You can open change streams against:

Target
Description

A collection

You can open a change stream cursor for a single collection (except system collections, or any collections in the admin, local, and config databases).

The examples on this page include both MongoDB driver and mongosh examples for opening and working with a change stream cursor for a single collection.

A database

You can open a change stream cursor for a single database (excluding admin, local, and config database) to watch for changes to all its non-system collections.

For the MongoDB driver method, refer to your driver documentation. See also the mongosh method db.watch().

A deployment

You can open a change stream cursor for a deployment (either a replica set or a sharded cluster) to watch for changes to all non-system collections across all databases except for admin, local, and config.

For the MongoDB driver method, refer to your driver documentation. See also the mongosh method Mongo.watch().

If the amount of active change streams opened against a database exceeds the connection pool size, you may experience notification latency. Each change stream holds a connection open with a getMore operation while waiting for the next event. To avoid latency, ensure that the pool size is greater than the number of open change streams. For details, see the maxPoolSize setting.

When a change stream is opened on a sharded cluster:

  • The mongos creates individual change streams on each shard. This behavior occurs regardless of whether the change stream targets a particular shard key range.

  • When the mongos receives change stream results, it sorts and filters those results. If needed, the mongos also performs a fullDocument lookup.

For best performance, limit the use of $lookup queries in change streams.

To open a change stream:

  • For a replica set, open the change stream from any data-bearing member.

  • For a sharded cluster, open the change stream from the mongos.

The following example opens a change stream for a collection and iterates over the cursor to retrieve the change stream documents. [1]

Iterate the change stream cursor to retrieve change events. See Change Stream Events for the change stream document format.

The change stream cursor remains open until one of the following occurs:

  • The cursor is explicitly closed.

  • An invalidate event occurs; for example, a collection drop or rename.

  • The connection to the MongoDB deployment closes or times out. See Behavior for more information.

  • If the deployment is a sharded cluster, a shard removal may cause an open change stream cursor to close. The closed change stream cursor may not be fully resumable.

Note

The lifecycle of an unclosed cursor is language-dependent.

[1] You can specify a startAtOperationTime to open the cursor at a particular point in time. If the specified starting point is in the past, it must be in the time range of the oplog.

Tip

The _id field of the change stream event document act as the resume token. Do not use the pipeline to modify or remove the change stream event's _id field.

Starting in MongoDB 4.2, change streams will throw an exception if the change stream aggregation pipeline modifies an event's _id field.

See Change Stream Events for more information on the change stream response document format.

By default, change streams only return the delta of fields during the update operation. However, you can configure the change stream to return the most current majority-committed version of the updated document.

The updateLookup operation reads the document identified by its shard key and document identifier from the collection. The collection is identified by its name and uses the collection data as it exists at the time the change stream is processed. Consider these scenarios:

  • If the collection is renamed, no document is returned.

  • If the collection is renamed and a new collection is created with the old name, then the lookup operation is performed on the new collection. If a matching document is found, it is returned.

Warning

For situations involving rapid deletions or traffic spikes, configuring fullDocument: "updateLookup" with a $match filter can cause 'Resume Token Not Found' errors. This occurs when a document deletion causes the fullDocument field to return a null value, because there is no matching document, which then prevents the change stream from finding the resume token.

Instead, use Pre- and Post-Images with fullDocumentBeforeChange: "whenAvailable" and fullDocument: "whenAvailable". See the Change Streams with Document Pre- and Post-Images section.

Note

If there are one or more majority-committed operations that modified the updated document after the update operation but before the lookup, the full document returned may differ significantly from the document at the time of the update operation.

However, the deltas included in the change stream document always correctly describe the watched collection changes that applied to that change stream event.

The fullDocument field for an update event may be missing if one of the following is true:

  • If the document is deleted or if the collection is dropped in between the update and the lookup.

  • If the update changes the values for at least one of the fields in that collection's shard key.

See Change Stream Events for more information on the change stream response document format.

Change streams are resumable by specifying a resume token to either resumeAfter or startAfter when opening the cursor.

Warning

When you resume a change stream with a resume token, use the same pipeline and options as when you originally generated the token. If you use a different change stream pipeline or different options, it might lead to unpredictable behavior, negatively impact data consistency, or prevent the change stream from resuming.

You can resume a change stream after a specific event by passing a resume token to resumeAfter when opening the cursor.

See Resume Tokens for more information on the resume token.

Important

  • The oplog must have enough history to locate the operation associated with the token or the timestamp, if the timestamp is in the past.

  • You cannot use resumeAfter to resume a change stream after an invalidate event (for example, a collection drop or rename) closes the stream. Instead, you can use startAfter to start a new change stream after an invalidate event.

You can start a new change stream after a specific event by passing a resume token to startAfter when opening the cursor. Unlike resumeAfter, startAfter can resume notifications after an invalidate event by creating a new change stream.

See Resume Tokens for more information on the resume token.

Important

  • The oplog must have enough history to locate the operation associated with the token or the timestamp, if the timestamp is in the past.

There are two types of resume tokens:

  • Event token: Identifies a specific change event. The change stream cursor generates an event token each time a change event occurs.

  • Highwatermark token: Represents a point in time without an associated change event. The server periodically generates highwatermark tokens to indicate that cluster time has advanced, even when no change events occur.

Tip

The server periodically advances the timestamp in highwatermark resume tokens. On idle shards with infrequent writes, this advancement might not occur frequently enough for some use cases. To advance the highwatermark timestamp more frequently, you can write no-op entries to the oplog on idle shards using the appendOplogNote command.

You can find resume tokens in multiple sources:

Source
Description

Each change event notification includes a resume token on the _id field.

The $changeStream aggregation stage includes a resume token on the cursor.postBatchResumeToken field.

This field only appears when using the aggregate command.

The getMore command includes a resume token on the cursor.postBatchResumeToken field.

Starting in MongoDB 4.2, change streams will throw an exception if the change stream aggregation pipeline modifies an event's _id field.

Tip

MongoDB provides a "snippet", an extension to mongosh, that decodes hex-encoded resume tokens.

You can install and run the resumetoken snippet from mongosh:

snippet install resumetoken
decodeResumeToken('<RESUME TOKEN>')

You can also run resumetoken from the command line (without using mongosh) if npm is installed on your system:

npx mongodb-resumetoken-decoder <RESUME TOKEN>

See the following for more details on:

Change event notifications include a resume token on the _id field:

{
"_id": {
"_data": "82635019A0000000012B042C0100296E5A1004AB1154ACACD849A48C61756D70D3B21F463C6F7065726174696F6E54797065003C696E736572740046646F63756D656E744B65790046645F69640064635019A078BE67426D7CF4D2000004"
},
"operationType": "insert",
"clusterTime": Timestamp({ "t": 1666193824, "i": 1 }),
"collectionUUID": new UUID("ab1154ac-acd8-49a4-8c61-756d70d3b21f"),
"wallTime": ISODate("2022-10-19T15:37:04.604Z"),
"fullDocument": {
"_id": ObjectId("635019a078be67426d7cf4d2"'),
"name": "Giovanni Verga"
},
"ns": {
"db": "test",
"coll": "names"
},
"documentKey": {
"_id": ObjectId("635019a078be67426d7cf4d2")
}
}

When using the aggregate command, the $changeStream aggregation stage includes a resume token on the cursor.postBatchResumeToken field:

{
"cursor": {
"firstBatch": [],
"postBatchResumeToken": {
"_data": "8263515EAC000000022B0429296E1404"
},
"id": Long("4309380460777152828"),
"ns": "test.names"
},
"ok": 1,
"$clusterTime": {
"clusterTime": Timestamp({ "t": 1666277036, "i": 1 }),
"signature": {
"hash": Binary(Buffer.from("0000000000000000000000000000000000000000", "hex"), 0),
"keyId": Long("0")
}
},
"operationTime": Timestamp({ "t": 1666277036, "i": 1 })
}

The getMore command also includes a resume token on the cursor.postBatchResumeToken field:

{
"cursor": {
"nextBatch": [],
"postBatchResumeToken": {
"_data": "8263515979000000022B0429296E1404"
},
"id": Long("7049907285270685005"),
"ns": "test.names"
},
"ok": 1,
"$clusterTime": {
"clusterTime": Timestamp( { "t": 1666275705, "i": 1 } ),
"signature": {
"hash": Binary(Buffer.from("0000000000000000000000000000000000000000", "hex"), 0),
"keyId": Long("0")
}
},
"operationTime": Timestamp({ "t": 1666275705, "i": 1 })
}

Change streams can benefit architectures with reliant business systems, informing downstream systems once data changes are durable. For example, change streams can save time for developers when implementing Extract, Transform, and Load (ETL) services, cross-platform synchronization, collaboration functionality, and notification services.

For deployments enforcing Authentication on Self-Managed Deployments and authorization:

  • To open a change stream against specific collection, applications must have privileges that grant changeStream and find actions on the corresponding collection.

    { resource: { db: <dbname>, collection: <collection> }, actions: [ "find", "changeStream" ] }
  • To open a change stream on a single database, applications must have privileges that grant changeStream and find actions on all non-system collections in the database.

    { resource: { db: <dbname>, collection: "" }, actions: [ "find", "changeStream" ] }
  • To open a change stream on an entire deployment, applications must have privileges that grant changeStream and find actions on all non-system collections for all databases in the deployment.

    { resource: { db: "", collection: "" }, actions: [ "find", "changeStream" ] }

Change streams only notify on data changes that have persisted to a majority of data-bearing members in the replica set. Change streams ensure that notifications trigger only for majority-committed changes that are durable in failure scenarios.

For example, consider a 3-member replica set with a change stream cursor opened against the primary. If a client issues an insert operation, the change stream only notifies the application of the data change once that insert has persisted to a majority of data-bearing members.

If an operation is associated with a transaction, the change event document includes the txnNumber and the lsid.

Change streams use simple binary comparisons unless an explicit collation is provided.

Starting in MongoDB 5.3, during range migration, change stream events are not generated for updates to orphaned documents.

Starting in MongoDB 6.0, you can use change stream events to output the version of a document before and after changes (the document pre- and post-images):

  • The pre-image is the document before it was replaced, updated, or deleted. There is no pre-image for an inserted document.

  • The post-image is the document after it was inserted, replaced, or updated. There is no post-image for a deleted document.

  • Enable changeStreamPreAndPostImages for a collection using db.createCollection(), create, or collMod. For example, when using the collMod command:

    db.runCommand( {
    collMod: <collection>,
    changeStreamPreAndPostImages: { enabled: true }
    } )

Pre- and post-images are not available for a change stream event if the images were:

  • Not enabled on the collection at the time of a document update or delete operation.

  • Removed after the pre- and post-image retention time set in expireAfterSeconds.

    • The following example sets expireAfterSeconds to 100 seconds on an entire cluster:

      use admin
      db.runCommand( {
      setClusterParameter:
      { changeStreamOptions: {
      preAndPostImages: { expireAfterSeconds: 100 }
      } }
      } )

      Note

      The setClusterParameter command is not supported in MongoDB Atlas clusters. For information on Atlas support for all commands, see Unsupported Commands in Atlas.

    • The following example returns the current changeStreamOptions settings, including expireAfterSeconds:

      db.adminCommand( { getClusterParameter: "changeStreamOptions" } )
    • Setting expireAfterSeconds to off uses the default retention policy: pre- and post-images are retained until the corresponding change stream events are removed from the oplog.

    • If a change stream event is removed from the oplog, then the corresponding pre- and post-images are also deleted regardless of the expireAfterSeconds pre- and post-image retention time.

Additional considerations:

  • Enabling pre- and post-images consumes storage space and adds processing time. Only enable pre- and post-images if you need them.

  • Limit the change stream event size to less than 16 mebibytes. To limit the event size, you can:

    • Limit the document size to 8 megabytes. You can request pre- and post-images simultaneously in the change stream output if other change stream event fields like updateDescription are not large.

    • Request only post-images in the change stream output for documents up to 16 mebibytes if other change stream event fields like updateDescription are not large.

    • Request only pre-images in the change stream output for documents up to 16 mebibytes if:

      • document updates affect only a small fraction of the document structure or content, and

      • do not cause a replace change event. A replace event always includes the post-image.

  • To request a pre-image, you set fullDocumentBeforeChange to required or whenAvailable in db.collection.watch(). To request a post-image, you set fullDocument using the same method.

  • Pre-images are written to the config.system.preimages collection.

    • The config.system.preimages collection may become large. To limit the collection size, you can set expireAfterSeconds time for the pre-images as shown earlier.

    • To monitor the size of config.system.preimages, connect to a shard node on a sharded cluster or a mongod node on a replica set. Then, run the following commands:

      use config
      db.system.preimages.totalSize()
      db.system.preimages.stats()

      Note

      You must have the collStats privilege action on the config.system.preimages collection to run these commands.

      To run these commands on an MongoDB Atlas deployment, you must have the atlasAdmin role.

    • Pre-images are removed asynchronously by a background process.

Important

Backward-Incompatible Feature

Starting in MongoDB 6.0, if you are using document pre- and post-images for change streams, you must disable changeStreamPreAndPostImages for each collection using the collMod command before you can downgrade to an earlier MongoDB version.

Tip

For complete examples with the change stream output, see Change Streams with Document Pre- and Post-Images.

If the initialSyncMethod parameter for the cluster is fileCopyBased, then there is no impact on change stream listeners.

If initialSyncMethod is logical and a change stream is opened on a newly synchronized node and reads events from a point in time earlier than the completion of the logical initial sync, the pre- and post-images may be missing.

Back

Limitations

On this page