Query Aggregates
Use aggregates for counts, sums, and summaries over projection rows.
Basic aggregate query
queries:
unread_notification_count:
from: user_notifications
input:
user_id: { type: string, required: true }
where:
user_id: { eq: input.user_id }
read: { eq: false }
group_by: [user_id]
aggregate:
count: { count: notification_id }
limit: 1The aggregate: block maps output field names to aggregate functions:
| Function | Description |
|---|---|
count | COUNT(col) |
sum | SUM(col) |
avg | AVG(col) |
min | MIN(col) |
max | MAX(col) |
Revenue summary
queries:
show_revenue_summary:
from: show_attendance
input:
show_id: { type: string, required: true }
where:
show_id: { eq: input.show_id }
refunded: { eq: false }
group_by: [show_id]
aggregate:
total_revenue: { sum: price_cents }
ticket_count: { count: ticket_id }
average_price: { avg: price_cents }
limit: 1Every aggregate query needs group_by. Without it, the query fails to compile or returns incorrect results.
coalesce_zero
Aggregate results on empty groups return NULL. Use coalesce_zero: true to convert NULL aggregates to 0:
queries:
unread_notification_count:
from: user_notifications
input:
user_id: { type: string, required: true }
where:
user_id: { eq: input.user_id }
read: { eq: false }
group_by: [user_id]
aggregate:
count: { count: notification_id }
coalesce_zero: true
limit: 1Without coalesce_zero, a user with no matching rows gets an empty result set, not { count: 0 }. If callers expect a number, enable coalesce_zero.
Aggregate anti-pattern
Warning: Do not use
fields: - count: colto compute aggregates. This is silently dropped.
# WRONG — silently ignored
fields:
- count: notification_idAlways use the top-level aggregate: block with group_by. If every query returns 1 or NULL, this is the most likely cause.
Next steps
- Filters & Joins — filter before aggregating
- Best Practices — staleness and empty-result handling
- Examples — revenue and leaderboard queries