Skip to content

Constant Keys

A constant key allows all events of a given type to accumulate into a single read model instance, regardless of which event source the events originate from. This is useful for global aggregates, system-wide counters, and singleton read models.

Use UsingConstantKey(string value) to specify a fixed key value for a from block:

public class GlobalCounterProjection : IProjectionFor<GlobalCounter>
{
public void Define(IProjectionBuilderFor<GlobalCounter> builder) => builder
.From<OrderPlaced>(_ => _
.UsingConstantKey("global")
.Count(m => m.TotalOrders));
}

Every OrderPlaced event, from every event source, updates the single GlobalCounter instance with the key "global".

The read model is a normal record or class. The constant key becomes its _id in the underlying store:

public record GlobalCounter(int TotalOrders);

Constant keys work with all counting and arithmetic functions, making them ideal for global aggregates:

public class SiteStatisticsProjection : IProjectionFor<SiteStatistics>
{
public void Define(IProjectionBuilderFor<SiteStatistics> builder) => builder
.From<UserRegistered>(_ => _
.UsingConstantKey("site")
.Count(m => m.TotalUsers))
.From<UserLoggedIn>(_ => _
.UsingConstantKey("site")
.Increment(m => m.ActiveSessions))
.From<UserLoggedOut>(_ => _
.UsingConstantKey("site")
.Decrement(m => m.ActiveSessions));
}
public record SiteStatistics(
int TotalUsers,
int ActiveSessions);

Use UsingConstantParentKey(string value) when working with child collections and you want all events to target the same parent read model:

public class TeamActivityProjection : IProjectionFor<Team>
{
public void Define(IProjectionBuilderFor<Team> builder) => builder
.Children(m => m.Members, children => children
.IdentifiedBy(e => e.UserId)
.From<UserJoined>(_ => _
.UsingConstantParentKey("main-team")
.Set(m => m.Name).To(e => e.UserName)));
}
StrategyMethodWhen to use
Event source ID(default)Each event stream is one instance
Event propertyUsingKey(e => e.Property)Property on the event identifies instance
Event contextUsingKeyFromContext(c => c.Property)Event context property identifies instance
CompositeUsingCompositeKey<T>(...)Multiple values together form identity
ConstantUsingConstantKey("value")All events update the same instance
using Cratis.Chronicle.Projections;
[EventType]
public record PageViewed(string PageUrl);
[EventType]
public record ButtonClicked(string ButtonId);
[EventType]
public record FormSubmitted(string FormId);
public record EngagementMetrics(
int PageViews,
int ButtonClicks,
int FormSubmissions);
public class EngagementMetricsProjection : IProjectionFor<EngagementMetrics>
{
public void Define(IProjectionBuilderFor<EngagementMetrics> builder) => builder
.From<PageViewed>(_ => _
.UsingConstantKey("metrics")
.Count(m => m.PageViews))
.From<ButtonClicked>(_ => _
.UsingConstantKey("metrics")
.Count(m => m.ButtonClicks))
.From<FormSubmitted>(_ => _
.UsingConstantKey("metrics")
.Count(m => m.FormSubmissions));
}

This projection collects engagement events from all users and event sources into a single EngagementMetrics document with the key "metrics".