Skip to main content

Writing Database Queries

info

This guide covers common query patterns using Drizzle ORM. For comprehensive documentation, see the Drizzle ORM Query Guide.

Basic Queries

Queries are centralized in src/server/db/queries.ts:

import { db } from ".";
import { eq, and, like } from "drizzle-orm";
import { users } from "./schema";

// Find by ID
export const getUserById = async (id: string) => {
return await db.query.users.findFirst({
where: eq(users.id, id),
});
};

// Find with conditions
export const findUsers = async (query: string) => {
return await db.query.users.findMany({
where: like(users.name, `%${query}%`),
columns: {
id: true,
name: true,
email: true,
},
});
};

Inserting Data

// Single insert
export const createUser = async (data: NewUser) => {
return await db.insert(users)
.values(data)
.returning();
};

// Batch insert
export const createManyUsers = async (data: NewUser[]) => {
return await db.insert(users)
.values(data)
.returning();
};

Updating Records

// Update by ID
export const updateUser = async (id: string, data: Partial<User>) => {
return await db.update(users)
.set(data)
.where(eq(users.id, id))
.returning();
};

// Conditional update
export const verifyEmail = async (email: string) => {
return await db.update(users)
.set({ emailVerified: true })
.where(eq(users.email, email))
.returning();
};

Deleting Records

// Delete by ID
export const deleteUser = async (id: string) => {
return await db.delete(users)
.where(eq(users.id, id))
.returning();
};

// Conditional delete
export const deleteInactiveUsers = async () => {
return await db.delete(users)
.where(eq(users.emailVerified, false))
.returning();
};

Relations and Joins

// Get user with related data
export const getUserWithSessions = async (id: string) => {
return await db.query.users.findFirst({
where: eq(users.id, id),
with: {
sessions: true,
accounts: true,
},
});
};

Complex Queries

// Advanced filtering
export const findActiveUsers = async () => {
return await db.query.users.findMany({
where: and(
eq(users.emailVerified, true),
eq(users.twoFactorEnabled, false)
),
orderBy: (users, { desc }) => [desc(users.createdAt)],
limit: 10,
});
};

Best Practices

  1. Centralize Queries

    • Keep queries in queries.ts
    • Group related queries together
    • Export typed results
  2. Type Safety

    • Use Drizzle's type inference
    • Define return types for complex queries
    • Validate input data
  3. Performance

    • Select only needed columns
    • Use appropriate indexes
    • Limit result sets when possible
Query Organization

For larger applications, consider organizing queries by domain:

// src/server/db/queries/users.ts
export const userQueries = {
getById: async (id: string) => {...},
create: async (data: NewUser) => {...},
update: async (id: string, data: Partial<User>) => {...},
};
warning

Remember to:

  • Handle database errors appropriately
  • Validate input data before queries
  • Use transactions for related operations