bun-query-builder

Select Queries

On this page 18

Learn how to retrieve data from your database with bun-query-builder.

Basic Select

// Select all columns
const users = await db.selectFrom('users').get()

// Select specific columns
const userNames = await db
  .selectFrom('users')
  .select(['id', 'name', 'email'])
  .get()

// Select with alias
const result = await db
  .selectFrom('users')
  .select(['name as userName', 'email as userEmail'])
  .get()

Distinct Queries

// Get distinct values
const uniqueCities = await db
  .selectFrom('users')
  .distinct()
  .select(['city'])
  .get()

// Distinct on specific column
const result = await db
  .selectFrom('users')
  .distinctOn('department')
  .select(['department', 'name'])
  .get()

Ordering Results

// Order ascending
const users = await db
  .selectFrom('users')
  .orderBy('name', 'asc')
  .get()

// Order descending
const latestPosts = await db
  .selectFrom('posts')
  .orderByDesc('created_at')
  .get()

// Shorthand for latest/oldest
const newest = await db.selectFrom('posts').latest().get()
const oldest = await db.selectFrom('posts').oldest().get()

// Random order
const randomUsers = await db
  .selectFrom('users')
  .inRandomOrder()
  .limit(5)
  .get()

// Multiple order conditions
const sorted = await db
  .selectFrom('users')
  .orderBy('department', 'asc')
  .orderBy('name', 'asc')
  .get()

Limiting Results

// Limit results
const topTen = await db
  .selectFrom('users')
  .limit(10)
  .get()

// Offset and limit for pagination
const page2 = await db
  .selectFrom('users')
  .offset(10)
  .limit(10)
  .get()

Aggregations

// Count all records
const totalUsers = await db.selectFrom('users').count()

// Count with condition
const activeCount = await db
  .selectFrom('users')
  .where({ active: true })
  .count()

// Average
const avgAge = await db
  .selectFrom('users')
  .where({ active: true })
  .avg('age')

// Sum
const totalRevenue = await db
  .selectFrom('orders')
  .where({ status: 'completed' })
  .sum('total')

// Max and Min
const highestScore = await db.selectFrom('users').max('score')
const lowestScore = await db.selectFrom('users').min('score')

Pagination

Standard Pagination

const page = await db
  .selectFrom('users')
  .paginate(20) // 20 per page

console.log(page.data)        // Array of users
console.log(page.total)       // Total records
console.log(page.perPage)     // 20
console.log(page.currentPage) // Current page number
console.log(page.lastPage)    // Last page number

Simple Pagination

// More efficient for large datasets (no total count)
const page = await db
  .selectFrom('users')
  .simplePaginate(20)

console.log(page.data)
console.log(page.hasMorePages)

Cursor Pagination

// Best for infinite scroll / real-time feeds
const page = await db
  .selectFrom('posts')
  .cursorPaginate(cursor, 20)

console.log(page.data)
console.log(page.nextCursor)
console.log(page.prevCursor)

Chunking Large Datasets

// Process large datasets in chunks
await db.selectFrom('users').chunk(100, async (users) => {
  for (const user of users) {
    await processUser(user)
  }
})

// Chunk by ID for better performance
await db.selectFrom('users').chunkById(100, async (users) => {
  await processBatch(users)
})

// Process each record individually
await db.selectFrom('users').eachById(async (user) => {
  await processUser(user)
})

Relations

Eager Loading

// Load related data
const users = await db
  .selectFrom('users')
  .with('posts')
  .get()

// Load multiple relations
const users = await db
  .selectFrom('users')
  .with('posts', 'comments', 'profile')
  .get()

// Nested relations
const users = await db
  .selectFrom('users')
  .with('posts.comments')
  .get()

Constrained Eager Loading

// Eager load with constraints
const users = await db
  .selectFrom('users')
  .with({
    posts: (qb) => qb
      .where('published', '=', true)
      .orderBy('created_at', 'desc')
  })
  .get()

Counting Relations

// Get count of related records
const users = await db
  .selectFrom('users')
  .withCount('posts')
  .get()

// Access count
users.forEach(user => {
  console.log(`${user.name} has ${user.posts_count} posts`)
})

Filtering by Relations

// Users that have at least one post
const usersWithPosts = await db
  .selectFrom('users')
  .has('posts')
  .get()

// Users that don't have any posts
const usersWithoutPosts = await db
  .selectFrom('users')
  .doesntHave('posts')
  .get()

// Users with published posts
const activeAuthors = await db
  .selectFrom('users')
  .whereHas('posts', (qb) => qb.where('published', '=', true))
  .get()

Query Scopes

// Define scopes on your model
const User = {
  name: 'User',
  table: 'users',
  scopes: {
    active: (qb) => qb.where({ status: 'active' }),
    verified: (qb) => qb.where({ email_verified_at: ['IS NOT', null] }),
    premium: (qb) => qb.where({ subscription: 'premium' }),
  }
}

// Use scopes in queries
const premiumUsers = await db
  .selectFrom('users')
  .scope('active')
  .scope('premium')
  .get()

Soft Deletes

// Include soft deleted records
const allUsers = await db
  .selectFrom('users')
  .withTrashed()
  .get()

// Only soft deleted records
const deletedUsers = await db
  .selectFrom('users')
  .onlyTrashed()
  .get()

Next Steps

Released under the MIT License.