MongoDB Tutorial 0/120 lessons ~6 min read Lesson 99

    Event Data Storage

    Event storage is the backbone of event-sourced architectures, audit trails and CQRS systems: every state change becomes an immutable, append-only document.

    Course progress0%
    Focus
    5 guided sections
    Practice signal
    Examples included
    Career prep
    Foundation builder

    Introduction

    Event storage is the backbone of event-sourced architectures, audit trails and CQRS systems: every state change becomes an immutable, append-only document. MongoDB's append-friendly write path, time-series collections and powerful aggregations make it a strong default for event stores up to billions of events.

    Compared to dedicated event stores (Kafka, EventStoreDB), MongoDB gives you flexible projections, ad-hoc replays, and rich queries out of the box — at the cost of slightly less throughput at extreme scale.

    Understanding the topic

    Designing an event store on MongoDB:

    • Append-only collection — no updates, no deletes; $set is forbidden by convention and validators.
    • Monotonic event id via { aggregateId, version } — unique compound index ensures ordering.
    • Event envelope{ id, aggregateId, type, version, ts, actor, payload }.
    • Projections — materialized read models built via change streams or scheduled $merge.
    • Change streams — push-based feed of new events to downstream consumers.
    • Snapshots — periodic state snapshots in a side collection to bound replay cost.

    Informative example

    Append + project pattern with change streams:

    js
    // Append (idempotent with optimistic lock on version)
    await db.events.insertOne({
    _id: ulid(),
    aggregateId, type: "OrderPaid", version: nextVersion,
    ts: new Date(), actor, payload: { amount, currency }
    });
    // Unique index that enforces ordering
    db.events.createIndex({ aggregateId: 1, version: 1 }, { unique: true });
    // Project — change stream rebuilds the orders_read model
    db.events.watch([
    { $match: { "fullDocument.type": { $in: ["OrderPaid", "OrderShipped"] } } }
    ]).on("change", c => projectIntoReadModel(c.fullDocument));

    Real-world use

    Many ledger, audit and "what changed?" systems run on MongoDB event stores. Change streams + materialized views give you CQRS without operating Kafka.

    Best practices

    • Mark the events collection append-only with a $jsonSchema validator that forbids updates outside the writer service.
    • Snapshot aggregates every N events so replays stay cheap.
    • Use change streams (resumable from a token) so projectors survive restarts.
    • Store actor + correlation id on every event — the audit story is the killer feature.
    Ready to mark this lesson complete?Track your journey across the entire course.