Skip to main content

MongoDB Provider

The MongoDB provider implements IDocumentPersistenceProvider for flexible document storage with aggregation pipeline support, change streams, and integrated projection/snapshot/outbox stores.

Before You Start

Event sourcing requires a replica set

If you use the MongoDB event store, MongoDB must run as a replica set — a single-node replica set is enough, and no additional members are required.

Appending two or more events in one call commits them inside a transaction, so that a batch lands all-or-nothing and a stream can never contain a partial prefix. MongoDB offers transactions only on a replica set. On a standalone server the driver rejects the write and the append fails with:

Standalone servers do not support transactions.

The failure is easy to miss in early development because it does not affect every write. Appending a single event is one document, needs no transaction, and succeeds on a standalone server — so a prototype that saves one event at a time works, and begins failing only once an aggregate raises two events in a single operation.

MongoDB Atlas always runs as a replica set, so this affects self-hosted deployments. To convert a local standalone server, start it with --replSet rs0 and run rs.initiate() once.

The other MongoDB stores — snapshots, projections, saga, inbox, outbox, CDC — do not require this.

Installation

dotnet add package Excalibur.Data.MongoDB

Dependencies: Excalibur.Data.Abstractions, MongoDB.Driver

Quick Start

using Microsoft.Extensions.DependencyInjection;

// Data persistence provider (fluent builder)
services.AddExcaliburMongoDb(mongo =>
{
mongo.ConnectionString("mongodb://localhost:27017")
.DatabaseName("MyApp");
});

All MongoDB subsystems use the fluent builder pattern with 4 canonical connection overloads:

// 1. Connection string (creates IMongoClient singleton internally)
mongo.ConnectionString("mongodb://localhost:27017");

// 2. Pre-configured IMongoClient instance
mongo.Client(existingMongoClient);

// 3. DI-aware client factory
mongo.ClientFactory(sp => sp.GetRequiredService<IMongoClient>());

// 4. Bind from appsettings.json section
mongo.BindConfiguration("MongoDB:Data");

Subsystem Entry Points

SubsystemEntry PointBuilder Interface
Dataservices.AddExcaliburMongoDb(mongo => ...)IMongoDBDataBuilder
Event Sourcinges.UseMongoDB(mongo => ...)IMongoDBEventSourcingBuilder
Sagasaga.UseMongoDB(mongo => ...)IMongoDBSagaBuilder
Inboxinbox.UseMongoDB(mongo => ...)IMongoDBInboxBuilder
Outboxoutbox.UseMongoDB(mongo => ...)IMongoDBOutboxBuilder
CDCcdc.UseMongoDB(mongo => ...)IMongoDbCdcBuilder
Leader Electionle.UseMongoDB(resourceName, mongo => ...)IMongoDBLeaderElectionBuilder

Legacy Registration Methods

The following standalone methods are still available for snapshots and projections:

MethodWhat It RegistersKey Options
AddMongoDbSnapshotStore(opts)ISnapshotStoreCollectionName
AddMongoDbProjectionStore<T>(connStr, dbName, opts?)IProjectionStore<T>CollectionName

Batch Projection Registration

Register multiple projections sharing the same connection in a single call:

services.AddMongoDbProjections("mongodb://localhost:27017", "MyApp", projections =>
{
projections.Add<OrderSummary>();
projections.Add<CustomerProfile>(o => o.CollectionName = "customers");
projections.Add<InventoryView>(o => o.CollectionName = "inventory");
});

Projections are stored flat at the document root. Framework metadata is isolated under a _projection nested object to avoid collisions with your projection properties. See Projections — Document Storage Format for details.

This follows the same pattern as AddElasticSearchProjections().

Aggregation Pipelines

MongoDB's aggregation framework is accessible through the document persistence provider:

var result = await documentProvider.ExecuteAggregationAsync(aggregationRequest, cancellationToken);

Index Management

await documentProvider.ExecuteIndexOperationAsync(indexRequest, cancellationToken);

See Also