Skip to content

Constant Keys

A constant key fixes the read model key to a literal string value, so all events of a given type accumulate into a single read model instance regardless of which event source they come from.

Use ConstantKey on the [FromEvent] attribute at the class level to route all matching events to a fixed read model instance:

using Cratis.Chronicle.Projections.ModelBound;
[FromEvent<OrderPlaced>(ConstantKey = "global")]
public record GlobalOrderSummary(
string LastCustomer,
DateTimeOffset LastOrderDate);

Every OrderPlaced event from every event source updates the same GlobalOrderSummary instance.

Count, Increment, and Decrement with ConstantKey

Section titled “Count, Increment, and Decrement with ConstantKey”

Count, Increment, and Decrement attributes also support ConstantKey for collecting events from all event sources into a single document:

using Cratis.Chronicle.Keys;
using Cratis.Chronicle.Projections.ModelBound;
public record SystemMetrics(
[Count<OrderPlaced>(ConstantKey = "metrics")]
int TotalOrders,
[Increment<UserLoggedIn>(ConstantKey = "metrics")]
[Decrement<UserLoggedOut>(ConstantKey = "metrics")]
int ActiveSessions,
[Count<ErrorOccurred>(ConstantKey = "metrics")]
int TotalErrors);

All three properties converge on the "metrics" document regardless of which user or order they come from.

You can mix regular key-based events with constant key events on the same read model:

[FromEvent<UserRegistered>]
public record UserDashboard(
[Key]
Guid UserId,
string Name,
[Count<OrderPlaced>(ConstantKey = "global-stats")]
int PlatformTotalOrders);

Note: When ConstantKey is set on a counter attribute, it affects which read model instance the counter updates — not the key of the read model the attribute belongs to. In this example, PlatformTotalOrders would update the document with key "global-stats", not the UserDashboard instance.

using Cratis.Chronicle.Events;
using Cratis.Chronicle.Projections.ModelBound;
// Events
[EventType]
public record ProductPurchased(string ProductId, decimal Amount);
[EventType]
public record ProductReturned(string ProductId, decimal Amount);
[EventType]
public record PageViewed(string PageUrl);
// Global read model
public record StoreMetrics(
[Count<ProductPurchased>(ConstantKey = "store")]
int TotalPurchases,
[Count<ProductReturned>(ConstantKey = "store")]
int TotalReturns,
[Increment<ProductPurchased>(ConstantKey = "store")]
[Decrement<ProductReturned>(ConstantKey = "store")]
int NetTransactions,
[Count<PageViewed>(ConstantKey = "store")]
int TotalPageViews);

All events from all users and products accumulate into the single StoreMetrics document with key "store".