| title | Aggregations |
|---|---|
| description | Perform aggregate calculations with the query builder. |
Perform aggregate calculations like COUNT, SUM, AVG, MIN, and MAX with full type safety.
Count records in a table:
import { createQueryBuilder } from 'bun-query-builder'
const db = createQueryBuilder<typeof schema>({ schema, meta })
// Count all records
const totalUsers = await db.selectFrom('users').count()
console.log(totalUsers) // 150
// Count with conditions
const activeUsers = await db
.selectFrom('users')
.where({ active: true })
.count()
// Count specific column (excludes NULL)
const usersWithEmail = await db.selectFrom('users').count('email')
// Count distinct values
const uniqueCountries = await db.selectFrom('users').countDistinct('country')Calculate the sum of a column:
// Sum of all order amounts
const totalRevenue = await db.selectFrom('orders').sum('amount')
console.log(totalRevenue) // 125000.50
// Sum with conditions
const yearlyRevenue = await db
.selectFrom('orders')
.where('created_at', '>=', '2024-01-01')
.sum('amount')Calculate the average of a column:
// Average age of users
const avgAge = await db.selectFrom('users').avg('age')
console.log(avgAge) // 32.5
// Average with conditions
const avgActiveUserAge = await db
.selectFrom('users')
.where({ active: true })
.avg('age')Get the maximum value:
// Maximum score
const maxScore = await db.selectFrom('users').max('score')
console.log(maxScore) // 9999
// Latest timestamp
const latestOrder = await db.selectFrom('orders').max('created_at')Get the minimum value:
// Minimum price
const minPrice = await db.selectFrom('products').min('price')
console.log(minPrice) // 9.99
// Earliest record
const firstOrder = await db.selectFrom('orders').min('created_at')Group results for aggregate calculations:
// Count users by country
const usersByCountry = await db
.selectFrom('users')
.select(['country', 'COUNT(*) AS count'])
.groupBy('country')
.get()
// [{ country: 'US', count: 50 }, { country: 'UK', count: 30 }, ...]
// Sum sales by category
const salesByCategory = await db
.selectFrom('orders')
.select(['category', 'SUM(amount) AS total'])
.groupBy('category')
.orderByDesc('total')
.get()
// Group by multiple columns
const salesByMonthAndCategory = await db
.selectFrom('orders')
.select([
'STRFTIME("%Y-%m", created_at) AS month',
'category',
'SUM(amount) AS total',
])
.groupBy(['month', 'category'])
.get()Filter grouped results:
// Find categories with more than 100 orders
const popularCategories = await db
.selectFrom('orders')
.select(['category', 'COUNT(*) AS order_count'])
.groupBy('category')
.having('COUNT(*)', '>', 100)
.get()
// Find users with high average order value
const highValueCustomers = await db
.selectFrom('orders')
.select(['user_id', 'AVG(amount) AS avg_order'])
.groupBy('user_id')
.having('AVG(amount)', '>', 500)
.get()Use raw SQL for complex aggregations:
// Custom aggregation
const results = await db
.selectFrom('orders')
.select([
'ROUND(AVG(amount), 2) AS avg_amount',
'ROUND(SUM(amount), 2) AS total',
'COUNT(*) AS count',
])
.first()
// Group by with raw expressions
const weeklyStats = await db
.selectFrom('orders')
.selectRaw(`
strftime('%Y-%W', created_at) AS week,
COUNT(*) AS orders,
SUM(amount) AS revenue
`)
.groupByRaw("strftime('%Y-%W', created_at)")
.get()Get multiple aggregates in one query:
// Multiple aggregates
const stats = await db
.selectFrom('products')
.select([
'COUNT(*) AS total',
'AVG(price) AS avg_price',
'MIN(price) AS min_price',
'MAX(price) AS max_price',
'SUM(stock) AS total_stock',
])
.first()
console.log(stats)
// {
// total: 100,
// avg_price: 49.99,
// min_price: 5.00,
// max_price: 999.99,
// total_stock: 5000
// }Combine aggregations with joins:
// Get authors with post counts
const authorStats = await db
.selectFrom('users')
.select([
'users.name',
'COUNT(posts.id) AS post_count',
'AVG(posts.views) AS avg_views',
])
.leftJoin('posts', 'users.id', 'posts.user_id')
.groupBy('users.id')
.orderByDesc('post_count')
.get()import { createQueryBuilder, buildDatabaseSchema, buildSchemaMeta } from 'bun-query-builder'
// Setup
const models = {
User: {
name: 'User',
table: 'users',
primaryKey: 'id',
attributes: {
id: { validation: { rule: {} } },
name: { validation: { rule: {} } },
country: { validation: { rule: {} } },
age: { validation: { rule: {} } },
active: { validation: { rule: {} } },
},
},
Order: {
name: 'Order',
table: 'orders',
primaryKey: 'id',
attributes: {
id: { validation: { rule: {} } },
user_id: { validation: { rule: {} } },
amount: { validation: { rule: {} } },
category: { validation: { rule: {} } },
created_at: { validation: { rule: {} } },
},
},
}
const schema = buildDatabaseSchema(models)
const meta = buildSchemaMeta(models)
const db = createQueryBuilder<typeof schema>({ schema, meta })
// Comprehensive analytics
async function getAnalytics() {
// Basic counts
const totalUsers = await db.selectFrom('users').count()
const activeUsers = await db.selectFrom('users').where({ active: true }).count()
// Order statistics
const orderStats = await db
.selectFrom('orders')
.select([
'COUNT(*) AS total_orders',
'SUM(amount) AS total_revenue',
'AVG(amount) AS avg_order_value',
'MIN(amount) AS min_order',
'MAX(amount) AS max_order',
])
.first()
// Users by country
const usersByCountry = await db
.selectFrom('users')
.select(['country', 'COUNT(*) AS count'])
.groupBy('country')
.orderByDesc('count')
.limit(10)
.get()
// Top categories by revenue
const topCategories = await db
.selectFrom('orders')
.select([
'category',
'COUNT(*) AS order_count',
'SUM(amount) AS revenue',
])
.groupBy('category')
.having('SUM(amount)', '>', 1000)
.orderByDesc('revenue')
.limit(5)
.get()
// Monthly revenue trend
const monthlyRevenue = await db
.selectFrom('orders')
.selectRaw(`
strftime('%Y-%m', created_at) AS month,
COUNT(*) AS orders,
SUM(amount) AS revenue
`)
.groupByRaw("strftime('%Y-%m', created_at)")
.orderBy('month')
.get()
return {
totalUsers,
activeUsers,
orderStats,
usersByCountry,
topCategories,
monthlyRevenue,
}
}
getAnalytics().then(console.log)