For AI agents: a documentation index is available at https://www.mongodb.com/docs/llms.txt — markdown versions of all pages are available by appending .md to any URL path.
Docs Menu

Configure Multi-Collection Initial Sync

initialSync lets an Atlas Stream Processing stream processor ingest preexisting documents in an Atlas collection as though they were insert changeEvent documents before it starts tailing the change stream. A single $source stage can now run initialSync against more than one collection at once.

This page compares single-collection and multi-collection sync characteristics, walks through configuring a multi-collection sync, and demonstrates a cross-cluster replication pipeline built on it.

The coll field of the $source stage accepts either a single collection name or an array of collection names. Every collection that you name in the array must belong to the database that you specify in the db field. You can't synchronize collections from more than one database in a single $source stage. The value you provide determines the sync scope:

Scope
$source Configuration
Behavior

Single collection

db: "app", coll: "orders"

Atlas Stream Processing synchronizes the one named collection.

Explicit list

db: "app", coll: ["a", "b", "c"]

Atlas Stream Processing synchronizes each collection in the list in the order in which you list them.

A multi-collection initialSync operation has the following traits:

  • Syncs collections in list order. With coll: ["a", "b", "c"], Atlas Stream Processing drains a's partitions before b's, and b's before c's, except where spillover fills idle capacity with partitions from a later collection.

  • Resumes without resyncing completed collections. Atlas Stream Processing tracks which collections have finished, so a restarted stream processor skips completed collections and resumes any in-progress collection from its last synchronized document. It might redeliver documents it already emitted, so design your sink to handle repeated documents idempotently.

  • Exposes granular collection level sync progress. stats().stats.operatorStats[0].targetStats reports sync progress and document counts for each target collection. To learn more, see Verify Initial Sync Progress.

Multi-collection initialSync differs from single-collection sync in ways that affect how you configure and operate your stream processor:

  • Parallelism is global, not per collection. Setting initialSync.parallelism caps the number of concurrent partition reads across the entire set of target collections, not per collection.

  • Catchup scope follows source scope. After the sync phase, Atlas Stream Processing opens a change stream matching the source's scope: a database-level change stream for a whole-database source, a cluster-level change stream for a whole-cluster source, or a filtered change stream for an explicit list of collections. You don't need to configure this separately.

  • A collection sync failure fails the whole processor. As with single-collection sync, if Atlas Stream Processing fails to synchronize any one collection in the list, the entire stream processor fails.

  • Some source-side configuration doesn't replicate to the destination. initialSync doesn't replicate indexes, collection options such as capped collections, time series collections, validators, or default collation, or view definitions. Create these on the destination before you start the stream processor. Atlas Stream Processing also doesn't discover collections that you create after the stream processor starts; the set of collections to synchronize is fixed at that point.

The following procedure uses two collections from the sample_analytics dataset: customers, which holds customer profiles, and accounts, which holds each customer's financial accounts. The procedure configures a stream processor that copies both collections from one Atlas cluster to another, then keeps them current as documents change.

Before you complete this procedure, you must have:

Run the commands in this section against your cluster. To connect, see Connect to a Cluster via mongosh.

Complete the following steps to prepare the source collections:

1

This procedure uses the customers and accounts collections from the sample_analytics dataset. To learn how to load sample data, see Import Sample Data Into Your Atlas Deployment.

2

Enable pre- and post-images on the customers and accounts collections, because the procedure's $source stage sets fullDocument: "required". Run the following commands against the cluster:

db.getSiblingDB("sample_analytics").runCommand({
collMod: "customers",
changeStreamPreAndPostImages: { enabled: true }
})
{ ok: 1, ... }
db.getSiblingDB("sample_analytics").runCommand({
collMod: "accounts",
changeStreamPreAndPostImages: { enabled: true }
})
{ ok: 1, ... }

To learn more about fullDocument: "required", see MongoDB Collection Change Stream.

Select the Atlas UI or mongosh to configure the stream processor.

1
  1. In the Atlas UI, go to the Stream Processing page for your Atlas project.

  2. Click Manage in the pane of your stream processing workspace that holds your Atlas connections to the source and destination clusters.

2
  1. Click Create stream processor.

  2. Select the Visual Builder.

3
  1. In the Source field, select your Atlas connection to the source cluster from the Connection drop-down list.

  2. In the JSON text box, configure the $source stage:

{
"$source": {
"connectionName": "<source-connection-name>",
"db": "sample_analytics",
"coll": ["customers", "accounts"],
"config": { "fullDocument": "required" },
"initialSync": { "enable": true }
}
}

The $source stage synchronizes existing documents in customers and accounts, in that order, then opens a change stream scoped to both collections:

  • coll: ["customers", "accounts"] sets the sync scope to both collections instead of one.

  • initialSync: { enable: true } turns on the sync phase before Atlas Stream Processing starts tailing the change stream.

  • fullDocument: "required" includes the current version of the document in every change event.

4
  1. In the Start building your pipeline pane, click + Custom stage.

  2. In the JSON text box, add a $replaceRoot stage:

{
"$replaceRoot": {
"newRoot": {
"$cond": {
"if": { "$eq": [{ "$meta": "stream.source.operationType" }, "delete"] },
"then": { "$meta": "stream.source.documentKey" },
"else": "$fullDocument"
}
}
}
}

The $replaceRoot stage prepares each event for the sink stage. It selects the document key for a delete event and the full document for every other event, so the $merge stage always receives a document that has an _id field.

5
  1. In the Sink field, select your Atlas connection to the destination cluster from the Connection drop-down list.

  2. In the JSON text box, configure the $merge stage:

{
"$merge": {
"into": {
"connectionName": "<destination-connection-name>",
"db": { "$meta": "stream.source.ns.db" },
"coll": { "$meta": "stream.source.ns.coll" }
},
"on": "_id",
"whenMatched": {
"$cond": {
"if": { "$eq": [{ "$meta": "stream.source.operationType" }, "delete"] },
"then": "delete",
"else": "replace"
}
},
"whenNotMatched": {
"$cond": {
"if": { "$eq": [{ "$meta": "stream.source.operationType" }, "delete"] },
"then": "discard",
"else": "insert"
}
}
}
}

The $merge stage writes each event to the collection on <destination-connection-name> that matches its source namespace:

  • db and coll read the source event's namespace metadata, so the same pipeline routes customers events to customers and accounts events to accounts.

  • whenMatched and whenNotMatched each branch on operation type, so the stage deletes, replaces, or inserts the destination document depending on the source event.

6
  1. In the Stream processor name field, enter replicate_analytics_sp.

  2. Select the tier for the stream processor. To choose a tier for your workload, see Atlas Stream Processing Tier Selection Guide.

7

Click Create stream processor.

8

On the Stream Processors tab, select replicate_analytics_sp and click Start.

Atlas Stream Processing synchronizes customers and accounts to <destination-connection-name>, then keeps both collections current. To learn more about starting, stopping, and monitoring stream processors, see Develop and Manage Stream Processors.

1

Use the connection string associated with your stream processing workspace to connect using mongosh.

  1. In the pane for your stream processing workspace, click Connect.

  2. In the Connect to your workspace dialog, select the Shell tab.

  3. Copy the connection string displayed in the dialog. It has the following format, where <atlas-stream-processing-url> is the URL of your stream processing workspace and <username> is the username of a database user with the atlasAdmin role:

    mongosh "mongodb://<atlas-stream-processing-url>/"
    --tls --authenticationDatabase admin --username <username>
    --password <password>
  4. Paste the connection string into your terminal and replace the <password> placeholder with the credentials for the user. Press Enter to connect to your stream processing workspace.

2

Declare a variable and assign it a $source stage specification that lists both collections and enables initialSync:

let s = {
$source: {
connectionName: "<source-connection-name>",
db: "sample_analytics",
coll: ["customers", "accounts"],
config: { fullDocument: "required" },
initialSync: { enable: true }
}
}

The $source stage synchronizes existing documents in customers and accounts, in that order, then opens a change stream scoped to both collections:

  • coll: ["customers", "accounts"] sets the sync scope to both collections instead of one.

  • initialSync: { enable: true } turns on the sync phase before Atlas Stream Processing starts tailing the change stream.

  • fullDocument: "required" includes the current version of the document in every change event.

3

Declare a variable and assign it a $replaceRoot stage specification:

let r = {
$replaceRoot: {
newRoot: {
$cond: {
if: { $eq: [{ $meta: "stream.source.operationType" }, "delete"] },
then: { $meta: "stream.source.documentKey" },
else: "$fullDocument"
}
}
}
}

The $replaceRoot stage prepares each event for the sink stage. It selects the document key for a delete event and the full document for every other event, so the $merge stage always receives a document that has an _id field.

4

Declare a variable and assign it a $merge stage specification that routes each event by its source namespace:

let m = {
$merge: {
into: {
connectionName: "<destination-connection-name>",
db: { $meta: "stream.source.ns.db" },
coll: { $meta: "stream.source.ns.coll" }
},
on: "_id",
whenMatched: { $cond: {
if: { $eq: [{ $meta: "stream.source.operationType" }, "delete"] },
then: "delete",
else: "replace"
} },
whenNotMatched: { $cond: {
if: { $eq: [{ $meta: "stream.source.operationType" }, "delete"] },
then: "discard",
else: "insert"
} }
}
}

The $merge stage writes each event to the collection on <destination-connection-name> that matches its source namespace:

  • db and coll read the source event's namespace metadata, so the same pipeline routes customers events to customers and accounts events to accounts.

  • whenMatched and whenNotMatched each branch on operation type, so the stage deletes, replaces, or inserts the destination document depending on the source event.

5

Use the sp.createStreamProcessor() method to create a stream processor named replicate_analytics_sp from the stages you defined:

sp.createStreamProcessor("replicate_analytics_sp", [s, r, m])

To assign the processor to a tier other than the tier of your stream processing workspace, pass a tier option in the options object. To choose a tier for your workload, see Atlas Stream Processing Tier Selection Guide.

6

Use the sp.processor.start() method to start replicate_analytics_sp:

sp.replicate_analytics_sp.start()
{ ok: 1 }

Atlas Stream Processing synchronizes customers and accounts to <destination-connection-name>, then keeps both collections current. To learn more about starting, stopping, and monitoring stream processors, see Develop and Manage Stream Processors.

After you start the stream processor, call sp.<processor-name>.stats() with the verbose option to view sync progress for each target collection. The source operator's entry in stats.operatorStats reports a targetStats array with one element per collection:

sp.replicate_analytics_sp.stats(
{ options: { verbose: true } }
).stats.operatorStats[0].targetStats
[
{
db: 'sample_analytics',
coll: 'customers',
inputMessageCount: Long('500'),
inputMessageSize: 672326,
initialSync: {
estimatedDocs: Long('500'),
copiedDocs: Long('251'),
status: 'in_progress'
}
},
{
db: 'sample_analytics',
coll: 'accounts',
inputMessageCount: Long('1746'),
inputMessageSize: 1883681,
initialSync: {
estimatedDocs: Long('1746'),
copiedDocs: Long('1746'),
status: 'completed'
}
}
]

Each target's initialSync.status field cycles through pending, in_progress, and completed as Atlas Stream Processing syncs that collection, or reports failed if the sync fails. estimatedDocs and copiedDocs report the estimated and completed document counts for that one collection.

To view total progress across every target collection, use the source operator's own initialSync field, which sums estimatedDocs and copiedDocs across all collections:

sp.replicate_analytics_sp.stats(
{ options: { verbose: true } }
).stats.operatorStats[0].initialSync
{ estimatedDocs: Long('2246'), copiedDocs: Long('1997') }

The preceding procedure replicates two collections between Atlas clusters. The following example applies the same pipeline to a different set of collections. Only the db and coll values in the $source stage change.

To learn more about the stages and concepts in this guide, see the following resources: