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
-
Centralize Queries
- Keep queries in
queries.ts
- Group related queries together
- Export typed results
- Keep queries in
-
Type Safety
- Use Drizzle's type inference
- Define return types for complex queries
- Validate input data
-
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