Configure camel casing for Chronicle and MongoDB
This how-to shows how to get camelCase field names in your read-model documents, the same for the documents Chronicle projections write and the documents Arc reads and writes in MongoDB.
Store read-model data with camelCase field names, and keep Chronicle and Arc’s MongoDB integration agreeing on every field and collection name.
Two things decide the stored names:
- The declared member names. C# properties are PascalCase by convention; Kotlin properties, Java record components and TypeScript fields are already camelCase.
- The naming policy. A naming policy can rename members and collections on the way to MongoDB. Chronicle’s projections and Arc’s MongoDB integration each apply one, and both must agree, or Arc reads fields and collections that Chronicle never writes.
Prerequisites
Section titled “Prerequisites”- An application using Arc with its MongoDB integration, and Chronicle for projections.
- For C#, the Cratis meta package setup (
AddCratis()andUseCratis()).
1. Configure the naming
Section titled “1. Configure the naming”Each backend does what its conventions call for:
var builder = WebApplication.CreateBuilder(args);
builder.AddCratis( configureArcBuilder: arcBuilder => arcBuilder.WithMongoDB( configureMongoDB: mongoBuilder => mongoBuilder.WithCamelCaseNamingPolicy()), configureChronicleBuilder: chronicleBuilder => chronicleBuilder.WithCamelCaseNamingPolicy());
var app = builder.Build();app.UseCratis();
await app.RunAsync();// Java record components are already camelCase, and a document stores each component under its// declared name, so this read model is persisted with the fields firstName and emailAddress.// Chronicle's JVM client has no camel-case option; field names need no configuration.//// Collection names need none either. With Arc's MongoDB integration and the Chronicle starter both// on the classpath, Arc's NamingPolicy also names the collection Chronicle projects this read model// into (Users), which is the collection Arc reads. To choose other names, declare your own Arc// NamingPolicy bean, or a Chronicle ReadModelNamingPolicy bean to name Chronicle's collections alone.public record User(String id, String firstName, String emailAddress) { }// Kotlin properties are already camelCase, and a document stores each property under its declared// name, so this read model is persisted with the fields firstName and emailAddress.// Chronicle's JVM client has no camel-case option; field names need no configuration.//// Collection names need none either. With Arc's MongoDB integration and the Chronicle starter both// on the classpath, Arc's NamingPolicy also names the collection Chronicle projects this read model// into (Users), which is the collection Arc reads. To choose other names, declare your own Arc// NamingPolicy bean, or a Chronicle ReadModelNamingPolicy bean to name Chronicle's collections alone.data class User(val id: String, val firstName: String, val emailAddress: String)import { field, Guid } from '@cratis/fundamentals';import { ArcApplication, key } from '@cratis/arc.core';import '@cratis/arc.chronicle';import { camelCaseMongoNamingPolicy } from '@cratis/arc.mongodb';
// Users/User.tsexport class User { @field(Guid) @key() id!: Guid; @field(String) firstName!: string; @field(String) emailAddress!: string;}
// main.tsconst builder = ArcApplication.createBuilder();builder.withMongoDB({ server: 'mongodb://localhost:27017', database: 'my-app', readModels: [User], namingPolicy: camelCaseMongoNamingPolicy});// The Chronicle client Arc creates stores a projected User in the collection this policy reads (users),// because withMongoDB is configured. No collectionName override is needed.builder.withChronicle({ connectionString: 'chronicle://localhost:35000', eventStore: 'my-app' });const app = await builder.build();await app.run();Turn on the camel case naming policy in both places: in Arc’s MongoDB integration and in the Chronicle client.
Kotlin and Java
Section titled “Kotlin and Java”Field names need no configuration. Documents store each property under its declared name, which is already camelCase, and the Chronicle JVM client has no camel case option.
Collection names need no configuration either. With Arc’s MongoDB integration and the Chronicle starter both on the classpath, Arc’s naming policy also names the collection Chronicle projects each read model into, so a projected User lands in Users, the collection Arc reads. This needs Chronicle.Kotlin 6.10.0 or later, which adds the read-model naming policy Arc supplies. To choose other names, declare your own Arc NamingPolicy bean (it flows through the same way), or a Chronicle ReadModelNamingPolicy bean to name Chronicle’s collections alone. An application that declares its own ChronicleOptions bean sets the policy itself with withReadModelNamingPolicy.
TypeScript
Section titled “TypeScript”Field names are already camelCase, and Chronicle’s TypeScript client writes them as declared. Set camelCaseMongoNamingPolicy on withMongoDB when your read models must match a C# service that uses camel case: it also camel-cases collection names (User becomes users).
Collection names follow Arc. When withMongoDB is configured, the Chronicle client Arc creates stores each projected read model listed in readModels in the collection Arc reads it from (users with camelCaseMongoNamingPolicy), so no collectionName override is needed. This needs @cratis/chronicle 6.29.0 or later, which adds the read-model naming policy Arc supplies. A read model Arc does not read keeps its identifier as the collection name. If you pass your own client to withChronicle, Arc leaves it alone: set readModelNamingPolicy on its ChronicleOptions yourself.
withMongoDB’s database must match the event store name, because Chronicle writes the default namespace’s read models to a database named after the event store.
2. What this gives you
Section titled “2. What this gives you”With this setup:
- Chronicle projections write read-model fields in camelCase.
- Arc’s MongoDB integration reads and writes the same camelCase field names.
- A property declared as
EmailAddressin C#, oremailAddressin Kotlin, Java or TypeScript, is stored asemailAddress.
3. Verify in MongoDB
Section titled “3. Verify in MongoDB”After your app runs and projections update read models, inspect the stored documents. You should see camelCase fields. If a query returns empty or half-filled read models, compare the stored collection and field names with the names your backend expects; a naming mismatch produces no error.