Grouping & Aggregation
Group documents and compute aggregated values.
Simple Grouping
Group by a single field:
konduct.collection<Order>()
.group {
by(Order::status)
accumulate {
"count" count Unit
"totalAmount" sum Order::amount
}
}
.toList()
Result structure:
Composite Key Grouping
Group by multiple fields:
konduct.collection<Sale>()
.group {
by {
"category" from Sale::category
"region" from Sale::region
}
accumulate {
"totalSales" sum Sale::amount
"avgSale" avg Sale::amount
}
}
.toList()
Result:
{
_id: { category: "Electronics", region: "North" },
category: "Electronics", // Auto-added
region: "North", // Auto-added
totalSales: 125000.0,
avgSale: 450.0
}
Time-Based Grouping
Group by time units:
konduct.collection<Sale>()
.group {
by(Sale::date, unit = TimeUnit.MONTH)
accumulate {
"monthlySales" sum Sale::amount
"orderCount" count Unit
}
}
.toList()
Expression-Based Aggregation
Use expressions in accumulators:
konduct.collection<OrderItem>()
.group {
by(OrderItem::orderId)
accumulate {
"totalRevenue" sum (OrderItem::quantity * OrderItem::price)
"totalDiscount" sum ((OrderItem::originalPrice - OrderItem::salePrice) * OrderItem::quantity)
"itemCount" count Unit
}
}
.toList()
All Accumulators
Numeric Aggregations
accumulate {
"total" sum Product::price
"average" avg Product::price
"minimum" min Product::price
"maximum" max Product::price
}
Counting
Array Accumulators
First & Last
konduct.collection<Order>()
.sort { Order::orderDate.asc() }
.group {
by(Order::customerId)
accumulate {
"firstOrder" first Order::orderDate
"lastOrder" last Order::orderDate
}
}
.toList()
Typed Results
Get type-safe results:
data class CategoryStats(
val _id: String,
val category: String,
val count: Int,
val avgPrice: Double,
val totalRevenue: Double
)
val results: List<CategoryStats> = konduct.collection<Product>()
.group<Product, CategoryStats> {
by(Product::category)
accumulate {
"count" count Unit
"avgPrice" avg Product::price
"totalRevenue" sum Product::price
}
}
.toList()
Or use into():
val results = konduct.collection<Product>()
.group {
by(Product::category)
accumulate {
"count" count Unit
"avgPrice" avg Product::price
}
}
.into<CategoryStats>()
.toList()
Real-World Examples
Customer Lifetime Value
konduct.collection<Order>()
.match { Order::status eq "completed" }
.group {
by(Order::customerId)
accumulate {
"totalSpent" sum Order::total
"orderCount" count Unit
"avgOrderValue" avg Order::total
"firstOrderDate" min Order::orderDate
"lastOrderDate" max Order::orderDate
}
}
.match { "totalSpent" gte 1000 }
.sort { "totalSpent".desc() }
.into<CustomerLTV>()
.toList()
Sales by Category and Month
konduct.collection<Sale>()
.group {
by {
"category" from Sale::category
"month" from Sale::date.month()
"year" from Sale::date.year()
}
accumulate {
"revenue" sum (Sale::quantity * Sale::price)
"units" sum Sale::quantity
"transactions" count Unit
}
}
.sort {
"year".desc()
"month".desc()
"revenue".desc()
}
.toList()
See Also
- Expressions - Use operators in aggregations
- Pagination - Paginate grouped results
- API Reference - Complete API docs