iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Change Streams

MongoDB Change Streams: real-time event stream of collection changes. Replica set + driver subscriptions, resume tokens, and the patterns.

MongoDB — change streams

EXAMPLE
// ===== Requirements =====
// - Replica set or sharded cluster (NOT standalone)
// - Driver that supports change streams (Node, Python, Go, Java, etc)

// ===== Watch a collection =====
const orders = db.collection('orders');
const stream = orders.watch();

for await (const change of stream) {
  console.log(change);
  /*
  {
    _id: { _data: '...' },   // resume token
    operationType: 'insert' | 'update' | 'replace' | 'delete' | 'invalidate' | 'rename',
    fullDocument: { ... },
    documentKey: { _id: ... },
    updateDescription: { updatedFields: {...}, removedFields: [...] },
    clusterTime: Timestamp,
    ns: { db: 'shop', coll: 'orders' },
  }
  */
}

// ===== Filter changes =====
const pipeline = [
  { $match: {
      operationType: { $in: ['insert', 'update'] },
      'fullDocument.status': 'paid',
  } },
];
const stream2 = orders.watch(pipeline, { fullDocument: 'updateLookup' });

// fullDocument: 'updateLookup' includes the document after update (extra cost).

// ===== Resume after disconnect =====
let resumeToken;
const stream3 = orders.watch([], { resumeAfter: resumeToken });
for await (const change of stream3) {
  resumeToken = change._id;   // save for restart
  // ...
}

// On restart, pass resumeAfter or startAfter to continue from where you stopped.

// ===== Watch at database / cluster level =====
db.watch();              // all collections in db
client.watch();          // all changes in the cluster

// ===== Use cases =====
// - Cache invalidation (Redis tied to Mongo)
// - Sync to a search index (Elastic / Meilisearch)
// - Real-time UI updates via WebSocket / SSE
// - Event-driven workflows (transactional outbox alternative)

// ===== Performance =====
// - Each watcher consumes an oplog tail; oplog sized for retention window
// - Heavy aggregation pipelines in watch() add CPU per change
// - Distributed worker should partition by collection or shard

// ===== Patterns =====
// - Persist resume token in durable store (DB / Redis)
// - Heartbeat / observe NO-OP events to verify liveness
// - Limit projection ({ $project } in the pipeline) to reduce bandwidth
// - One watcher per logical concern; do not multiplex

// ===== Pitfalls =====
// - Standalone server (change streams require replica set)
// - Long pause -> token expires -> needs full reset (lost events)
// - Heavy filtering done client-side instead of in the watch pipeline
// - Multiple watchers fighting for the same updates without coordination

Why it matters

Change Streams turn MongoDB into a change-data-capture source. Subscribe via watch(), persist resume tokens, filter via aggregation pipelines. Great for cache invalidation, search index sync, real-time UI. Requires replica set; mind oplog retention and token expiry.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
const stream = db.collection('orders').watch();
stream.on('change', e => console.log(e.operationType, e.fullDocument));
Try it Yourself »

Discussion

Loading…