Docs Menu
Docs Home
/ / /
C Driver
/

Monitor Data Changes

On this page

  • Overview
  • Sample Data
  • Open a Change Stream
  • Open a Change Stream Example
  • Modify the Change Stream Output
  • Match Specific Events Example
  • Modify Watch Behavior
  • Include Pre-Images and Post-Images
  • Additional Information
  • API Documentation

In this guide, you can learn how to use the C driver to monitor a change stream, allowing you to view real-time changes to your data. A change stream is a MongoDB Server feature that publishes data changes on a collection, database, or deployment. Your application can subscribe to a change stream and use events to perform other actions.

The examples in this guide use the restaurants collection in the sample_restaurants database from the Atlas sample datasets. To learn how to create a free MongoDB Atlas cluster and load the sample datasets, see the Get Started with Atlas guide.

To open a change stream, call one of the following functions that corresponds to the scope of events you want to observe:

  • mongoc_client_watch(): Monitors all changes in the MongoDB deployment

  • mongoc_database_watch(): Monitors changes in all collections in the database

  • mongoc_collection_watch(): Monitors changes in the collection

The following example opens a change stream on the restaurants collection and prints changes as they occur:

bson_t *pipeline = bson_new ();
const bson_t *doc;
mongoc_change_stream_t *change_stream =
mongoc_collection_watch (collection, pipeline, NULL);
while (true) {
bson_error_t error;
if (mongoc_change_stream_next (change_stream, &doc)) {
char *str = bson_as_canonical_extended_json (doc, NULL);
printf ("Received change: %s\n", str);
bson_free (str);
} else if (mongoc_change_stream_error_document (change_stream, &error, NULL)) {
printf("Got error on change stream: %s\n", error.message);
break;
}
}
bson_destroy (pipeline);
mongoc_change_stream_destroy (change_stream);

To begin watching for changes, run the application. Then, in a separate application or shell, perform a write operation on the restaurants collection. The following example updates a document in which the value of the name field is "Blarney Castle":

bson_t *filter = BCON_NEW ("name", BCON_UTF8 ("Blarney Castle"));
bson_t *update = BCON_NEW("$set", "{", "cuisine", BCON_UTF8 ("Irish"), "}");
mongoc_collection_update_one (collection, filter, update, NULL, NULL, NULL);

When you update the collection, the change stream application prints the change as it occurs. The printed change event resembles the following:

{
"_id": { ... },
"operationType": "update",
"clusterTime": { ... },
"ns": {
"db": "sample_restaurants",
"coll": "restaurants"
},
"updateDescription": {
"updatedFields": {
"cuisine": "Irish"
},
"removedFields": [],
"truncatedArrays": []
}
...
}

You can pass the pipeline parameter to any watch function to modify the change stream output. This parameter allows you to watch for only specified change events. Format the parameter as a list of objects, where each object represents an aggregation stage.

You can specify the following stages in the pipeline parameter:

  • $addFields

  • $match

  • $project

  • $replaceRoot

  • $replaceWith

  • $redact

  • $set

  • $unset

The following example uses the pipeline parameter to include a $match stage to open a change stream that records only update operations:

bson_t *pipeline = BCON_NEW (
"pipeline", "[",
"{", "$match", "{", "operationType", BCON_UTF8 ("update"), "}", "}",
"]");
const bson_t *doc;
mongoc_change_stream_t *change_stream =
mongoc_collection_watch (collection, pipeline, NULL);
while (mongoc_change_stream_next (change_stream, &doc)) {
char *str = bson_as_canonical_extended_json (doc, NULL);
printf ("Received change: %s\n", str);
bson_free (str);
}
bson_destroy (pipeline);
mongoc_change_stream_destroy (change_stream);

To learn more about modifying your change stream output, see the Modify Change Stream Output section in the MongoDB Server manual.

You can modify any watch function by passing options to the function call. If you don't specify any options, the driver does not customize the operation.

The following table describes options you can use to customize the behavior of the watch functions:

Option
Description

batchSize

Sets the number of documents to return per batch.

comment

Specifies a comment to attach to the operation.

fullDocument

Sets the fullDocument value. To learn more, see the Include Pre-Images and Post-Images section of this document.

fullDocumentBeforeChange

Sets the fullDocumentBeforeChange value. To learn more, see the Include Pre-Images and Post-Images section of this document.

maxAwaitTimeMS

Sets the maximum await execution time on the server for this operation, in milliseconds.

For a complete list of options you can use to configure the watch operation, see the watch method guide in the MongoDB Server manual.

Important

You can enable pre-images and post-images on collections only if your deployment uses MongoDB v6.0 or later.

By default, when you perform an operation on a collection, the corresponding change event includes only the delta of the fields modified by that operation. To see the full document before or after a change, specify the fullDocumentBeforeChange or the fullDocument options in your watch function call.

The pre-image is the full version of a document before a change. To include the pre-image in the change stream event, pass one of the following values to the fullDocumentBeforeChange option:

  • whenAvailable: The change event includes a pre-image of the modified document for change events only if the pre-image is available.

  • required: The change event includes a pre-image of the modified document for change events. If the pre-image is not available, the driver raises an error.

The post-image is the full version of a document after a change. To include the post-image in the change stream event, pass one of the following values to the fullDocument option:

  • updateLookup: The change event includes a copy of the entire changed document from some time after the change.

  • whenAvailable: The change event includes a post-image of the modified document for change events only if the post-image is available.

  • required: The change event includes a post-image of the modified document for change events. If the post-image is not available, the driver raises an error.

The following example calls the mongoc_collection_watch() function on a collection and includes the post-image of updated documents in the results by specifying the fullDocument option:

bson_t *pipeline = bson_new ();
bson_t *opts = BCON_NEW ("fullDocument", BCON_UTF8 ("updateLookup"));
const bson_t *doc;
mongoc_change_stream_t *change_stream =
mongoc_collection_watch (collection, pipeline, opts);
while (true) {
bson_error_t error;
if (mongoc_change_stream_next (change_stream, &doc)) {
char *str = bson_as_canonical_extended_json (doc, NULL);
printf ("Received change: %s\n", str);
bson_free (str);
} else if (mongoc_change_stream_error_document (change_stream, &error, NULL)) {
printf("Got error on change stream: %s\n", error.message);
break;
}
}
bson_destroy (pipeline);
bson_destroy (opts);
mongoc_change_stream_destroy (change_stream);

With the change stream application running, updating a document in the restaurants collection by using the preceding update example prints a change event resembling the following:

{
"_id": ...,
"operationType": "update",
"clusterTime": ...,
"wallTime": ...,
"fullDocument": {
"_id": {
...
},
"address": ...,
"borough": "Queens",
"cuisine": "Irish",
"grades": [ ... ],
"name": "Blarney Castle",
"restaurant_id": ...
},
"ns": {
"db": "sample_restaurants",
"coll": "restaurants"
},
"documentKey": {
"_id": ...
},
"updateDescription": {
"updatedFields": {
"cuisine": "Irish"
},
"removedFields": [],
"truncatedArrays": []
}
}

To learn more about pre-images and post-images, see Change Streams with Document Pre- and Post-Images in the MongoDB Server manual.

To learn more about change streams, see Change Streams in the MongoDB Server manual.

To learn more about any of the functions or types discussed in this guide, see the following API documentation:

Back

Access Data from a Cursor