0Pricing
MongoDB Academy · 강의

컬렉션에서 변경 스트림 열기

학습자는 컬렉션에서 watch()를 호출하고 비동기 반복을 사용해 Node.js 애플리케이션에서 이벤트 스트림을 소비합니다.

컬렉션에서 변경 스트림 열기은(는) CoddyKit의 무료 MongoDB Academy 강의입니다. 이것은 4개 중 1번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 MongoDB Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. MongoDB Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.

What Are Change Streams?

Change streams provide a real-time event feed of all insert, update, replace, delete, and invalidate operations on a MongoDB collection, database, or entire deployment. Introduced in MongoDB 3.6, they are built on top of the oplog (operation log)—the replica set's replication journal—but expose a high-level, resumable cursor API instead of requiring you to parse the raw oplog format.

Prerequisites for Change Streams

Change streams require a replica set or sharded cluster—they do not work on standalone MongoDB instances because they depend on the oplog. On MongoDB Atlas, all clusters (even the free tier M0) are replica sets, so change streams work out of the box. For local development, you need to start mongod with --replSet rs0 and initiate the replica set with rs.initiate() in mongosh.

// Verify you're on a replica set before using change streams
// In mongosh:
rs.status() // should show replica set members, not an error

// If running locally without a replica set, start one:
// mongod --replSet rs0 --port 27017 --dbpath /data/db
// Then in mongosh: rs.initiate()

Opening a Change Stream With watch()

Call collection.watch() to open a change stream on a specific collection. The method returns a ChangeStream cursor object that you can iterate using async iteration, the next() method, or event listeners. The stream stays open and delivers events as they occur. An empty watch() call with no pipeline receives all change event types on that collection.

const { MongoClient } = require('mongodb');
const client = new MongoClient(process.env.MONGODB_URI);

async function watchCollection() {
  const db = client.db('ecommerce');
  const orders = db.collection('orders');

  // Open a change stream on the orders collection
  const changeStream = orders.watch();

  console.log('Watching for changes...');
  // The stream is now open and ready to deliver events
  return changeStream;
}

Consuming Events With Async Iteration

The most readable way to consume change stream events in modern Node.js is with async iteration using for await...of. This syntax automatically handles the cursor's next() calls and pauses the loop between events. The loop runs indefinitely until the change stream is closed or an error occurs. Always wrap the loop in a try/finally to ensure the stream is closed when your process exits.

async function processChanges() {
  const changeStream = db.collection('orders').watch();
  try {
    for await (const change of changeStream) {
      console.log('Change received:', change.operationType);
      console.log('Document key:', change.documentKey._id);
      // Handle the change event
      await handleOrderChange(change);
    }
  } finally {
    await changeStream.close();
  }
}

Consuming Events With EventEmitter

Alternatively, you can use the change stream as a Node.js EventEmitter. This approach is familiar if you use streams elsewhere in your code. Register a 'change' event handler for normal events and an 'error' handler for connection issues. This style is useful when you want to react to events without blocking a function with an await loop.

const changeStream = db.collection('products').watch();

changeStream.on('change', (event) => {
  console.log('Product changed:', event.operationType, event.documentKey._id);
  if (event.operationType === 'update') {
    invalidateProductCache(event.documentKey._id);
  }
});

changeStream.on('error', (error) => {
  console.error('Change stream error:', error);
  // Implement reconnect logic or close gracefully
});

// Close when done
// changeStream.close();

Change Stream Scope: Collection, Database, Client

You can open change streams at three scopes: collection level (watches one collection), database level (watches all collections in a database), and client level (watches all databases and collections in the deployment). The broader the scope, the higher the event volume. Most applications watch specific collections to receive only the events they care about.

// Collection-level (most common)
const stream1 = db.collection('orders').watch();

// Database-level — all collections in 'ecommerce'
const stream2 = client.db('ecommerce').watch();

// Client-level — everything in the deployment
const stream3 = client.watch();

// Events at db/client scope include 'ns' field to identify which collection changed
for await (const change of stream2) {
  console.log('Changed collection:', change.ns.coll);
}

Change Stream Options: fullDocument

By default, update events only include the fields that changed (the update description), not the entire document. If you need the full updated document in the event payload, pass { fullDocument: 'updateLookup' } to watch(). This causes MongoDB to perform an additional lookup of the document after the update and include it in the change event. Be aware this adds latency and is a separate read after the event.

// Receive the full document in update events
const changeStream = db.collection('users').watch(
  [], // empty pipeline = all events
  { fullDocument: 'updateLookup' }
);

for await (const change of changeStream) {
  if (change.operationType === 'update') {
    // change.fullDocument is now the complete updated user document
    console.log('Updated user:', change.fullDocument.email);
    await syncToSearchIndex(change.fullDocument);
  }
}

Real-Time Dashboard Use Case

A classic use case for change streams is powering a live dashboard that shows new orders as they arrive. When a new order document is inserted, the change stream triggers, and your Node.js backend can push the update to connected clients via WebSocket or Server-Sent Events. This eliminates polling and provides true real-time updates without overloading the database with repeated queries.

// Server: push new orders to dashboard clients via WebSocket
async function startOrderWatcher(io) { // io = socket.io instance
  const changeStream = db.collection('orders').watch([
    { $match: { operationType: 'insert' } }
  ]);

  for await (const change of changeStream) {
    const newOrder = change.fullDocument;
    // Broadcast to all connected dashboard clients
    io.to('dashboard').emit('newOrder', {
      id: newOrder._id,
      customer: newOrder.customerId,
      amount: newOrder.total,
      timestamp: newOrder.createdAt
    });
  }
}

Event-Driven Microservices With Change Streams

Change streams can replace a message broker like Kafka or RabbitMQ for simple event-driven microservice patterns. When Service A writes to MongoDB, Service B watches the collection and reacts to changes. This avoids the operational complexity of a separate message bus for low-to-medium event volumes. However, for high-throughput use cases, dedicated message brokers offer better guarantees and higher throughput than change streams.

// Inventory service reacts to confirmed orders
async function inventoryWatcher() {
  const changeStream = db.collection('orders').watch([
    {
      $match: {
        operationType: 'update',
        'updateDescription.updatedFields.status': 'confirmed'
      }
    }
  ], { fullDocument: 'updateLookup' });

  for await (const change of changeStream) {
    const order = change.fullDocument;
    for (const item of order.items) {
      await reserveInventory(item.productId, item.quantity);
    }
  }
}

Closing a Change Stream Gracefully

Change streams consume a persistent connection to the MongoDB server. Always close them when your process shuts down or when you no longer need the stream. Call changeStream.close() which returns a Promise. For long-running applications, listen for process signals (SIGTERM, SIGINT) and close streams and clients before exiting to avoid resource leaks on the server side.

const changeStream = db.collection('events').watch();

// Graceful shutdown
process.on('SIGTERM', async () => {
  console.log('Shutting down...');
  await changeStream.close();
  await client.close();
  process.exit(0);
});

// Handle SIGINT (Ctrl+C in development)
process.on('SIGINT', async () => {
  await changeStream.close();
  await client.close();
  process.exit(0);
});

Change Streams vs Polling

Before change streams, applications relied on polling—periodically querying MongoDB to detect new or updated documents. Polling wastes resources (queries run even when nothing changed), introduces latency (the detection delay equals the poll interval), and scales poorly under high event rates. Change streams eliminate polling entirely: your application is notified immediately when data changes, consuming minimal resources when the collection is quiet. This makes change streams the preferred pattern for any feature that needs to react to data changes.

Quick Check

Test your understanding of MongoDB & NoSQL Databases concepts from this lesson.

Lesson Recap

In this lesson you learned: change streams provide a real-time event feed of all CRUD operations on a collection, database, or deployment, they require a replica set and are consumed via async iteration or EventEmitter, and the fullDocument option requests the complete updated document in update events. Next up we explore the structure of change event documents and how to handle each operation type.

자주 묻는 질문

“컬렉션에서 변경 스트림 열기” 강의는 무료인가요?

네 — “컬렉션에서 변경 스트림 열기” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 MongoDB Academy 강의 전체를 잠금 해제할 수 있습니다. MongoDB Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“컬렉션에서 변경 스트림 열기”에서 뭘 배우나요?

학습자는 컬렉션에서 watch()를 호출하고 비동기 반복을 사용해 Node.js 애플리케이션에서 이벤트 스트림을 소비합니다. 브라우저에서 직접 실행하는 실습 코드로 MongoDB Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

MongoDB Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 MongoDB Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 1번째 강의입니다.

“컬렉션에서 변경 스트림 열기” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 MongoDB Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 MongoDB Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 컬렉션에서 변경 스트림 열기
  2. 변경 이벤트 문서 구조
  3. 집계 파이프라인으로 이벤트 필터링하기
  4. 중단 후 변경 스트림 재개하기
← MongoDB Academy(으)로 돌아가기