0PricingLogin
Node.js Backend Development Bootcamp · Lesson

Building Read Models and Projections

Derive optimized query-side projections from the event stream and keep them eventually consistent.

Why Read Models Exist

In an event-sourced system, the write side stores facts as an append-only stream of events. That stream is great for capturing history but terrible for queries like "show me all open orders sorted by total".

The read side solves this. A read model (also called a projection) is a denormalized, query-optimized view derived purely from events. This is the Q in CQRS: commands mutate the event stream, queries hit read models.

  • One event stream can feed many read models, each shaped for a specific query.
  • Read models are disposable — you can delete and rebuild them from events at any time.
  • They are eventually consistent with the write side, not transactionally consistent.

A Projection Is a Left Fold

At its core, a projection is just a reduce over the event stream: you start with an initial state and apply each event in order to produce the next state.

Conceptually: readModel = events.reduce(apply, initialState). The apply function is a pure switch over event types. Anything you can fold, you can project.

// Pure projection: fold the event stream into a read model
const events = [
  { type: 'OrderPlaced', orderId: 'o1', total: 50 },
  { type: 'OrderPlaced', orderId: 'o2', total: 20 },
  { type: 'OrderPaid', orderId: 'o1' },
  { type: 'OrderCancelled', orderId: 'o2' },
];

function apply(state, event) {
  const next = { ...state };
  switch (event.type) {
    case 'OrderPlaced':
      next[event.orderId] = { status: 'placed', total: event.total };
      break;
    case 'OrderPaid':
      if (next[event.orderId]) next[event.orderId].status = 'paid';
      break;
    case 'OrderCancelled':
      delete next[event.orderId];
      break;
  }
  return next;
}

const readModel = events.reduce(apply, {});
console.log(readModel);
// { o1: { status: 'paid', total: 50 } }

All lessons in this course

  1. Events as the Source of Truth and the Append-Only Log
  2. Aggregates, Commands, and Domain Event Modeling
  3. Building Read Models and Projections
  4. Snapshots, Versioning, and Event Schema Evolution
← Back to Node.js Backend Development Bootcamp