Aller au contenu
Français

MongoJournal

Ce contenu n’est pas encore disponible dans votre langue.

Defined in: src/persistence/journals/MongoJournal.ts:76

Journal backed by MongoDB via the mongodb driver.

Optimistic concurrency rests on a unique index. append reads the current head and then inserts; the unique compound index on (persistenceId, sequenceNr) rejects a racing writer with server error 11000, which is translated back into JournalConcurrencyError. That is the same two-layer scheme the relational backends use — the head check for the ordinary case, a conditional write for the race — with the unique index playing the part a primary key plays there.

No transaction, deliberately. Appends are contiguous from the head, so two writers that agree on the head both try the same first sequence number: the loser’s insertMany fails on its first document and writes nothing, with ordered: true stopping the batch there. A partial append is therefore not reachable through contention, which is what a transaction would have been for — and skipping it keeps the backend usable on a standalone mongod, since MongoDB transactions require a replica set. A mid-batch infrastructure failure (a dropped connection after the second of five events) can still persist a prefix; the stream stays gap-free and the next append continues from the new head, so recovery is consistent, but the caller’s error does not mean “nothing was written”. Single-event appends — the common case — are atomic outright.

Payloads are stored as JSON text, not as native BSON. It costs the ability to query inside a payload, which the framework never does (it queries by persistence id, sequence number and tags), and it buys exact round-trip fidelity: BSON would reject or mangle a payload with dotted or $-prefixed keys, and would quietly change how undefined and dates come back. The other backends store JSON text too, so an event stream means the same thing everywhere.

Being a cross-process store, it exposes no in-process event bus, so the query layer polls — same as Postgres and Cassandra. Tag queries do use an index: see MongoQuery.

new MongoJournal(options?): MongoJournal

Defined in: src/persistence/journals/MongoJournal.ts:82

MongoJournalOptions = {}

MongoJournal

MongoStore.constructor

get serializer(): Serializer<unknown> | undefined

Defined in: src/persistence/journals/MongoJournal.ts:97

The configured payload serializer — read by MongoQuery so tag reads decode like the journal.

Serializer<unknown> | undefined

append<E>(persistenceId, events, expectedSeq, tags?): Promise<PersistentEvent<E>[]>

Defined in: src/persistence/journals/MongoJournal.ts:107

Append events to the stream of persistenceId, enforcing optimistic concurrency: the current highest sequence number MUST equal expectedSeq or the call throws JournalConcurrencyError. Returns the written events with their assigned sequence numbers.

E

string

readonly E[]

number

readonly string[]

Promise<PersistentEvent<E>[]>

Journal.append


close(): Promise<void>

Defined in: src/persistence/LazyStore.ts:66

Best-effort teardown; idempotent.

Promise<void>

Journal.close

MongoStore.close


delete(persistenceId, toSeq): Promise<void>

Defined in: src/persistence/journals/MongoJournal.ts:185

Delete events up to and including toSeq — used when compacting past a snapshot. Only ever a prefix, so what survives is a suffix that read still returns contiguously, and sequence numbers never rewind: highestSeq keeps reporting the high-water mark afterwards.

string

number

Promise<void>

Journal.delete


highestSeq(persistenceId): Promise<number>

Defined in: src/persistence/journals/MongoJournal.ts:176

Current highest sequence number for persistenceId — 0 if no events exist.

string

Promise<number>

Journal.highestSeq


openForQuery(): Promise<{ events: MongoCollectionLike<EventDocument>; }>

Defined in: src/persistence/journals/MongoJournal.ts:251

Open the store and hand the query layer the collection it needs — the one seam MongoQuery needs into an otherwise private surface.

Promise<{ events: MongoCollectionLike<EventDocument>; }>


persistenceIds(): Promise<string[]>

Defined in: src/persistence/journals/MongoJournal.ts:213

No persistenceIdsPaginated counterpart, deliberately. distinct is the only way to reach the id set through this driver shim and it has no cursor, so a “page” would still be the whole distinct result sliced in JS — the fallback in the query layer already does exactly that, and doing it here would only hide that no work was pushed down. A real push-down wants a $group/$sort/$limit pipeline, which means widening MongoCollectionLike with aggregate; that is a change worth making on its own evidence, not as a side effect of #156.

Promise<string[]>

Journal.persistenceIds


read<E>(persistenceId, fromSeq, toSeq?): Promise<PersistentEvent<E>[]>

Defined in: src/persistence/journals/MongoJournal.ts:160

Return the events in [fromSeq, …, toSeq], ascending by sequence number. toSeq defaults to the current highest sequence number. Both bounds are inclusive — fromSeq is the first event returned, not an “after” cursor.

Ordering and contiguity are part of the contract, and replay enforces them (#122). Consecutive entries must differ by exactly one, every sequenceNr must be a safe integer ≥ 1, and nothing may fall outside the requested window. delete compacts a prefix, never a hole in the middle, so a gap inside the returned slice can only mean a defect — a missing ORDER BY, a half-written append, a store someone else can write. replayState raises JournalIntegrityError instead of folding it, because an actor that recovers from a shuffled or holed stream reaches a state that never existed and then fails every later persist with a JournalConcurrencyError that has no visible cause.

E

string

number

number

Promise<PersistentEvent<E>[]>

Journal.read