Skip to main content
MongoDB CDC ingestion lets a StarTree Pinot realtime table consume MongoDB Change Streams directly, without first copying changes through Kafka, Kinesis, Pulsar, or another durable stream. If you have not chosen an ingestion path yet, start at Connect MongoDB, which compares this connector against the Kafka and mongodump routes.
This connector is intended for advanced realtime ingestion designs where the MongoDB source namespaces, partitioning, credentials, and replay window are explicitly managed. If you only need to consume Debezium-formatted MongoDB events from Kafka, use the Debezium decoder instead.

How It Works

The connector maps each configured MongoDB source partition to one Pinot partition group:
Use the StarTree MongoDB CDC consumer factory:
Pinot controllers resolve source-partition metadata and checkpoints. Pinot servers open and resume MongoDB Change Stream cursors for the partitions they own. Pinot replication creates another cursor per partition replica, so plan source-side Change Stream load as:
For sharded MongoDB deployments, a cursor opened through mongos can fan out to every shard. Plan closer to:

Source-Partition Contract

MongoDB Change Streams do not expose Kafka-style durable partitions. The connector therefore requires a manifest of physical, disjoint MongoDB namespaces. Follow these rules:
  • Partition IDs are dense, stable integers: 0, 1, 2, and so on.
  • Every descriptor has a globally unique and immutable sourceId, such as atlas-prod-a/app/orders-00.
  • _id values must be globally unique across the configured namespaces.
  • Every insert, update, replace, and delete for one primary key must stay in the same source partition for that key’s lifetime.
  • Do not remove, renumber, rebind, or repartition an active source partition. Create a new Pinot table, snapshot/backfill, catch up CDC, and cut over queries instead.
  • Do not use hash(_id) % currentPartitionCount for upstream routing. Increasing the partition count would move existing keys and break upsert partition affinity.
A common routing pattern is to encode the source partition into the immutable _id:
New partitions can receive only newly created IDs. Existing IDs must continue to route to their original namespace.

Prerequisites

  • MongoDB Atlas, a replica set, or a sharded cluster. Standalone mongod processes do not support Change Streams.
  • MongoDB credentials available to Pinot controllers and servers.
  • find and changeStream permissions on every source namespace.
  • If you use registry mode, find on the manifest collection and listCollections on source databases.
  • If you use outputMode=full_document, MongoDB Server 6.0 or later with Change Stream pre/post-images enabled.
  • An oplog and post-image retention window longer than the maximum Pinot outage and recovery window.

Static Manifest Mode

Use static mode when the source partition list is fixed. Omit partitionDiscoveryMode and set sourcePartitions to a JSON array encoded as a string.
In this mode, every descriptor requires:

Registry Manifest Mode

Use partitionDiscoveryMode=mongodb_manifest when an upstream routing service can append new physical bucket collections. The table config allowlists connection references and points Pinot at one authoritative registry document.
Example registry document:
Registry mode fails closed if an existing descriptor changes, a partition is removed, a partition ID is skipped, a namespace UUID changes, or a later generation mutates an old prefix. maxPartitionCount is a safety limit that prevents a malformed registry from creating unbounded Pinot segments or MongoDB cursors.

Output Modes

For full_document, enable post-images on every source collection:
Source documents must not contain any of the connector’s reserved fields:

Tuning Options and Defaults

Every option below is optional. The values shown in the examples on this page are the defaults unless noted. Size the MongoDB URI’s maxPoolSize for the maximum number of MongoDB CDC partitions that can be active in one Pinot JVM across all tables, plus controller metadata requests. Partitions sharing an identical connection string and timeout settings share one client and pool; distinct credentials, endpoints, or timeouts get their own.

Rejected Options

The connector fails closed rather than accept these:

Current-State Upsert Example

Schema:
Realtime upsert config:
comparisonColumns uses the connector-generated comparison value so MongoDB event order is preserved. strictReplicaGroup is required so a query sees a consistent upsert view for each partition.

Capturing Initial Offsets

When creating a table with auto.offset.reset=largest, the controller captures a starting boundary for each partition that does not already provide initialOffset. To include historical documents:
  1. Capture an exact resume boundary for each MongoDB namespace.
  2. Snapshot/backfill the historical data up to that boundary.
  3. Configure each descriptor with the captured initialOffset.
  4. Start realtime CDC consumption from those offsets.
For step 1, the connector JAR exposes a bootstrap API that prints the descriptor-ready Extended JSON. Run it from a short Java program with the shaded connector JAR on the classpath, using the same fullDocument and maxAwaitTimeMs values as the target table:
Capture each namespace independently, paste the printed document in as that descriptor’s initialOffset, then snapshot that namespace. Registry mode also needs the printed collectionUuid. Boundary capture is per namespace and is not a transactionally atomic cut across collections. Descriptor example:
Do not substitute a bare clusterTime; the offset must include the resume token and its safe logical time.

Adding Capacity

To append a partition safely:
  1. Create a new, quiescent physical namespace.
  2. Capture the namespace UUID and exact initial offset.
  3. Append only the next highest dense partitionId.
  4. Wait until Pinot reports the new partition group consuming on the required replicas.
  5. Route only new keys to the new namespace.
Do not configure a primary-key segmentPartitionConfig on a table whose MongoDB source-partition count can grow. A growing partition count changes key ownership for older rows.

Troubleshooting