Counters
Counters track how many times events occur or increment/decrement numeric values. The language provides three counter operations: count, increment, and decrement.
The count operation increments a property by 1 each time an event occurs:
count {Property}Example
Section titled “Example”from PageViewed count ViewCount LastViewedAt = $eventContext.occurredEach PageViewed event increases ViewCount by 1.
Increment
Section titled “Increment”The increment operation increases a property by 1:
increment {Property}Example
Section titled “Example”from UserLoggedIn increment LoginCount LastLogin = $eventContext.occurredDecrement
Section titled “Decrement”The decrement operation decreases a property by 1:
decrement {Property}Example
Section titled “Example”from ItemConsumed decrement RemainingStock LastConsumed = $eventContext.occurredDifference Between Count and Increment
Section titled “Difference Between Count and Increment”While count and increment both add 1, they have semantic differences:
count: Counts occurrences of a specific event (conceptually counting events)increment: Increases a value (conceptually modifying state)
In practice, they behave identically but express different intent.
Multiple Counters
Section titled “Multiple Counters”You can use multiple counter operations in the same event:
from OrderPlaced increment TotalOrders count OrderCount add TotalRevenue by totalExamples
Section titled “Examples”User Activity Tracking
Section titled “User Activity Tracking”projection User => UserReadModel from UserRegistered Name = name Email = email
from UserLoggedIn count LoginCount LastLogin = $eventContext.occurred
from UserProfileViewed increment ProfileViewCountInventory Management
Section titled “Inventory Management”projection Product => ProductReadModel from ProductCreated Name = name StockLevel = initialStock
from ItemAdded increment StockLevel
from ItemSold decrement StockLevel count SalesCount
from ItemReturned increment StockLevel decrement SalesCountBlog Post Engagement
Section titled “Blog Post Engagement”projection BlogPost => BlogPostReadModel from PostPublished Title = title Content = content
from PostViewed count ViewCount
from PostLiked increment LikeCount
from PostUnliked decrement LikeCount
from CommentAdded count CommentCountAccount Balance (Alternative to Arithmetic)
Section titled “Account Balance (Alternative to Arithmetic)”projection Account => AccountReadModel from AccountOpened AccountNumber = accountNumber Balance = initialBalance
from DepositMade increment TransactionCount add Balance by amount
from WithdrawalMade increment TransactionCount subtract Balance by amountForum User Reputation
Section titled “Forum User Reputation”projection ForumUser => ForumUserReadModel from UserJoined Username = username
from QuestionPosted count QuestionsPosted
from AnswerPosted count AnswersPosted
from UpvoteReceived increment Reputation
from DownvoteReceived decrement ReputationTask Completion Tracking
Section titled “Task Completion Tracking”projection Project => ProjectReadModel from ProjectCreated Name = name
from TaskAdded increment TotalTasks
from TaskCompleted increment CompletedTasks decrement RemainingTasks
from TaskAdded increment RemainingTasksProperty Requirements
Section titled “Property Requirements”The target property must be a numeric type:
intlongdecimaldoublefloat
Attempting to use counters on non-numeric properties will result in a validation error.
Initial Values
Section titled “Initial Values”Counter properties should have an initial value. Declare counter targets such as LoginCount or ProfileViews as numeric properties on the read model, starting at 0, so the first counter operation produces 1.
Best Practices
Section titled “Best Practices”- Initialize to Zero: Ensure counter properties start at 0 in the read model
- Use Count for Events: Use
countwhen tracking event occurrences - Use Increment/Decrement for State: Use
increment/decrementfor state changes - Combine with Timestamps: Pair counters with timestamps for richer tracking
- Validate Decrements: Ensure decrements won’t result in negative values if that’s not valid for your domain
- Consider Arithmetic: For more complex numeric operations, use Arithmetic operations
See Also
Section titled “See Also”- Arithmetic - Add and subtract operations with variable amounts
- Property Mapping - Setting properties to specific values