Skip to content

Commit 23d6ad8

Browse files
authored
Merge pull request #1121 from eventflow/docs-improve-mongodb
Improve documentation for MongoDB
2 parents 54d640c + ae9bcbd commit 23d6ad8

File tree

1 file changed

+123
-10
lines changed

1 file changed

+123
-10
lines changed

Documentation/integration/mongodb.md

Lines changed: 123 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,134 @@
22
layout: default
33
title: MongoDB
44
parent: Integration
5-
nav_order: 2
5+
nav_order: 3
66
---
77

8-
Mongo DB
9-
========
8+
# MongoDB
109

11-
To setup EventFlow Mongo DB, install the NuGet package `EventFlow.MongoDB` and add this to your EventFlow setup.
10+
Use the `EventFlow.MongoDB` integration when you want EventFlow to persist events,
11+
read models, or snapshots in MongoDB. This guide walks through the recommended
12+
package, configuration patterns, collection preparation, and a few
13+
troubleshooting tips.
14+
15+
## Prerequisites
16+
17+
- A MongoDB server (Replica Set recommended for production). EventFlow works with
18+
MongoDB 5.0 or newer; the integration tests run against Mongo2Go, which ships
19+
with MongoDB 6.x.
20+
- A .NET application already wired with `EventFlow`.
21+
- Network access and credentials that allow reads and writes to the target database.
22+
23+
## Install the NuGet package
24+
25+
Add the MongoDB integration to every project that configures EventFlow.
26+
27+
```bash
28+
dotnet add package EventFlow.MongoDB
29+
```
30+
31+
## Configure EventFlow
32+
33+
The `ConfigureMongoDb` helpers make sure a single `IMongoDatabase` instance is
34+
registered with DI. You can pass a connection string, a custom `MongoClient`, or
35+
an `IMongoDatabase` factory.
36+
37+
```csharp
38+
// Program.cs / Startup.cs
39+
var mongoUrl = new MongoUrl(Configuration.GetConnectionString("eventflow-mongo"));
40+
var mongoClient = new MongoClient(mongoUrl);
41+
42+
services.AddEventFlow(ef => ef
43+
.ConfigureMongoDb(mongoClient, mongoUrl.DatabaseName)
44+
.UseMongoDbEventStore() // Events
45+
.UseMongoDbSnapshotStore() // Snapshots (optional)
46+
.UseMongoDbReadModel<UserReadModel>() // Read models
47+
.UseMongoDbReadModel<UserNicknameReadModel, UserNicknameLocator>());
48+
```
49+
50+
### Read models must implement `IMongoDbReadModel`
51+
52+
Mongo-backed read models use optimistic concurrency on a `Version` field and
53+
store documents in a single collection per read model type. Implement the
54+
interface and optionally override the collection name.
55+
56+
```csharp
57+
[MongoDbCollectionName("users")]
58+
public class UserReadModel : IMongoDbReadModel,
59+
IAmReadModelFor<UserAggregate, UserId, UserCreated>
60+
{
61+
public string Id { get; set; } = default!; // MongoDB document _id
62+
public long? Version { get; set; }
63+
public string Username { get; set; } = default!;
64+
65+
public Task ApplyAsync(
66+
IReadModelContext context,
67+
IDomainEvent<UserAggregate, UserId, UserCreated> domainEvent,
68+
CancellationToken cancellationToken)
69+
{
70+
Id = domainEvent.AggregateIdentity.Value;
71+
Username = domainEvent.AggregateEvent.Username.Value;
72+
return Task.CompletedTask;
73+
}
74+
}
75+
```
76+
77+
If you omit `MongoDbCollectionNameAttribute`, EventFlow defaults to
78+
`ReadModel-[TypeName]` for the collection name.
79+
80+
### Snapshots
81+
82+
Calling `UseMongoDbSnapshotStore()` stores aggregate snapshots in the same
83+
database. Each snapshot is kept in a shared `eventflow-snapshots` collection,
84+
including the version number and metadata required for upgrades.
85+
86+
## Prepare collections and indexes
87+
88+
EventFlow registers an `IMongoDbEventPersistenceInitializer` that sets up the
89+
unique index on `(AggregateId, AggregateSequenceNumber)` in the events
90+
collection. Run it once during application startup or as a migration step.
1291

1392
```csharp
14-
// ...
15-
.ConfigureMongoDb(client, "database-name")
16-
// ...
93+
using (var scope = services.BuildServiceProvider().CreateScope())
94+
{
95+
scope.ServiceProvider
96+
.GetRequiredService<IMongoDbEventPersistenceInitializer>()
97+
.Initialize();
98+
}
99+
```
100+
101+
Read model collections are created lazily. When running in production, pre-create
102+
them with the appropriate indexes for your query workload (for example, on
103+
`Username` or `TenantId` fields) and size any capped collections ahead of time.
104+
105+
## Local development quickstart
106+
107+
Spin up a disposable MongoDB container and point your connection string at
108+
`mongodb://localhost:27017/eventflow`.
109+
110+
```bash
111+
docker run --rm -p 27017:27017 --name eventflow-mongo mongo:7
17112
```
18113

19-
After setting up Mongo DB support in EventFlow, you can continue to configure it.
114+
Integration tests live in `Source/EventFlow.MongoDB.Tests` if you need sample
115+
fixtures for seeding data or running smoke tests.
116+
117+
## Troubleshooting
118+
119+
- **Duplicate key errors on event writes** – ensure the initializer created the
120+
index or rerun `Initialize()`. Unique index collisions usually indicate a
121+
concurrency issue in the aggregate.
122+
- **Read model updates never land** – confirm your read models implement
123+
`IMongoDbReadModel` and expose a writable `Version` property. Without it, the
124+
optimistic concurrency check fails silently.
125+
- **Connection spikes on cold start** – reuse a singleton `MongoClient` instead
126+
of recreating it per request so the driver can manage pooling.
127+
- **Changing collection names** – rename carefully and migrate existing data;
128+
EventFlow does not perform collection migrations automatically.
129+
130+
## See also
131+
132+
- [Event stores](event-stores.md#mongo-db)
133+
- [Read model stores](read-stores.md#mongo-db)
134+
- [Snapshots](../additional/snapshots.md)
20135

21-
- [Event store](event-stores.md#mongo-db)
22-
- [Read model store](read-stores.md#mongo-db)

0 commit comments

Comments
 (0)