Skip to content

Keys

Keys identify individual projection instances. They determine which read model instance to create or update when an event occurs.

Specify which property from the event identifies the instance:

from UserRegistered key userId
Name = name
Email = email

The userId from the event becomes the key for the UserReadModel instance.

Keys can be specified inline on the from statement:

from OrderPlaced key orderId
Total = total
Status = "Pending"

When using multiple events in one from statement, each can have its own key:

from EventA key idA, EventB key idB, EventC
automap

For more complex scenarios, use block syntax:

from OrderPlaced
key orderId
Total = total

Use composite keys when multiple properties together identify an instance:

from OrderCreated
key OrderKey
CustomerId = customerId
OrderNumber = orderNumber
Total = total
key {TypeName}
{Property} = {expression}
{Property} = {expression}
...

The {TypeName} must match a complex type defined in your read model schema.

Composite Key with Event Context and Causation

Section titled “Composite Key with Event Context and Causation”

You can include event context and causation values in composite keys:

from LineItemAdded
key LineItemKey
OrderId = orderId
LineNumber = lineNumber
SequenceNumber = $eventContext.sequenceNumber
CreatedBy = $causedBy.subject
Product = productName
Quantity = quantity

If no key is specified, the event source ID is used as the key:

from UserRegistered
Name = name

Equivalent to:

from UserRegistered key $eventSourceId
Name = name

Children must always specify an identifier:

children members identified by userId
from UserAddedToGroup key userId
parent groupId
Role = role

The id userId specifies the child identifier property, while key userId specifies which event property to use.

Keys can be:

  • Property paths: userId, order.id, data.customerId
  • Event source ID: $eventSourceId
  • Event context: $eventContext.correlationId
from ProductCreated key productId
Name = name
Price = price
from AccountCreated key $eventSourceId
AccountNumber = accountNumber
Balance = 0.0
from OrderPlaced key order.id
Total = order.total
CustomerId = customerId
projection OrderLine => OrderLineReadModel
from LineItemAdded
key OrderLineKey {
OrderId = orderId
ProductId = productId
}
Quantity = quantity
UnitPrice = unitPrice
LineTotal = total
from ReservationMade
key ReservationKey {
HotelId = hotelId
RoomNumber = roomNumber
CheckInDate = checkInDate
}
GuestName = guestName
Nights = nights
children orderLines identified by lineNumber
from LineItemAdded key lineNumber
parent orderId
Product = productName
Quantity = quantity
Price = price

Use literal "value" to fix the key to a constant string. All events matching the from block update the same read model instance regardless of event source:

from OrderPlaced
key literal "global"
count TotalOrders

Every OrderPlaced event, from every event source, increments TotalOrders on the single document with key "global".

Literal keys also work inline on the from statement:

from UserLoggedIn key literal "site-stats"
count TotalLogins

Literal keys are especially useful with counter and arithmetic operations for global aggregates:

projection SiteMetrics => SiteMetricsReadModel
from UserRegistered
key literal "metrics"
count TotalUsers
from UserLoggedIn
key literal "metrics"
increment ActiveSessions
from UserLoggedOut
key literal "metrics"
decrement ActiveSessions
from OrderPlaced
key literal "metrics"
count TotalOrders
add TotalRevenue by amount

All events from all users accumulate into the single SiteMetricsReadModel document with key "metrics".

Simple Keys (inline):

  • Single property identifies the instance
  • Property name is clear from context
  • Most common scenario

Block Keys:

  • When you want visual separation
  • Complex event structures
  • Personal preference for readability

Composite Keys:

  • Multiple properties together form identity
  • Natural keys from business domain
  • Partitioning or sharding scenarios
  • Complex relationships

Event Source ID:

  • Each event stream represents one instance
  • Aggregate-based event sourcing
  • One-to-one event stream to read model

Literal (Constant) Keys:

  • All events update the same instance
  • Global counters and system-wide aggregates
  • Singleton read models
  1. Be Explicit: Specify keys when not using event source ID
  2. Match Domain: Use business-meaningful identifiers
  3. Composite for Complexity: Use composite keys for multi-property identifiers
  4. Consistent Naming: Use consistent key property names across events
  5. Document Composites: Composite keys benefit from clear type names
  6. Literal for Globals: Use literal keys for system-wide or global aggregates