Counters
Counters track how many times events occur or increment/decrement numeric values. Chronicle 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:
public class UserReadModel{ public string Name { get; set; } public int LoginCount { get; set; } = 0; // Initialize to 0 public int ProfileViews { get; set; } = 0;}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