Drizzle์ select *๋ฅผ ์ฌ์ฉํ๋ ๋์ ํญ์ select ์ ์ ์ปฌ๋ผ์ ๋ช
์์ ์ผ๋ก ๋์ดํฉ๋๋ค.
์ด๋ ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ์์ ํ๋ ์์๋ฅผ ๋ณด์ฅํ๊ธฐ ์ํด ๋ด๋ถ์ ์ผ๋ก ํ์ํ๋ฉฐ, ์ผ๋ฐ์ ์ผ๋ก ์ข์ ๊ดํ์ผ๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
SQL Select
Drizzle์ ํ์
์์ ์ฑ๊ณผ ์กฐํฉ ๊ฐ๋ฅ์ฑ์ ์ ์งํ๋ฉด์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฐ์ฅ SQL๊ณผ ์ ์ฌํ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
๋ชจ๋ ๋ฐฉ์ธ์ ๋๋ถ๋ถ์ ์ฟผ๋ฆฌ ๊ธฐ๋ฅ๊ณผ ์ญ๋์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ง์ํ๋ฉฐ,
์์ง ์ง์ํ์ง ์๋ ๊ฒ์ ๊ฐ๋ ฅํ sql ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ์ฌ ์ฌ์ฉ์๊ฐ ์ถ๊ฐํ ์ ์์ต๋๋ค.
๋ค์ ์์ ์์๋ ๋ค์๊ณผ ๊ฐ์ด ์ ์๋ users ํ
์ด๋ธ์ด ์๋ค๊ณ ๊ฐ์ ํ๊ฒ ์ต๋๋ค:
import { pgTable, serial, text } from 'drizzle-orm/pg-core';
export const users = pgTable('users', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
age: integer('age'),
});๊ธฐ๋ณธ select
๋ชจ๋ ์ปฌ๋ผ์ ํฌํจํ์ฌ ํ ์ด๋ธ์ ๋ชจ๋ ํ ์ ํ:
const result = await db.select().from(users);
/*
{
id: number;
name: string;
age: number | null;
}[]
*/select "id", "name", "age" from "users";๊ฒฐ๊ณผ ํ์ ์ ์ปฌ๋ผ์ null ํ์ฉ ์ฌ๋ถ๋ฅผ ํฌํจํ์ฌ ํ ์ด๋ธ ์ ์๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์๋์ผ๋ก ์ถ๋ก ๋ฉ๋๋ค.
๋ถ๋ถ select
๊ฒฝ์ฐ์ ๋ฐ๋ผ ํ
์ด๋ธ์์ ์ปฌ๋ผ์ ์ผ๋ถ๋ง ์ ํํ๊ณ ์ถ์ ์ ์์ต๋๋ค.
.select() ๋ฉ์๋์ ์ ํ ๊ฐ์ฒด๋ฅผ ์ ๊ณตํ์ฌ ์ด๋ฅผ ์ํํ ์ ์์ต๋๋ค:
const result = await db.select({
field1: users.id,
field2: users.name,
}).from(users);
const { field1, field2 } = result[0];select "id", "name" from "users";SQL๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ํ ์ด๋ธ ์ปฌ๋ผ๋ฟ๋ง ์๋๋ผ ์์์ ํํ์์ ์ ํ ํ๋๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค:
const result = await db.select({
id: users.id,
lowerName: sql<string>`lower(${users.name})`,
}).from(users);select "id", lower("name") from "users";sql<string>์ ์ง์ ํจ์ผ๋ก์จ ํ๋์ ์์ ํ์
์ด string์์ Drizzle์ ์๋ ค์ฃผ๋ ๊ฒ์
๋๋ค.
์๋ชป ์ง์ ํ๋ฉด(์: ๋ฌธ์์ด๋ก ๋ฐํ๋ ํ๋์ sql<number>๋ฅผ ์ฌ์ฉ) ๋ฐํ์ ๊ฐ์ด ์์ ํ์
๊ณผ ์ผ์นํ์ง ์์ต๋๋ค.
Drizzle์ ์ ๊ณต๋ ํ์
์ ๋ค๋ฆญ์ ๊ธฐ๋ฐ์ผ๋ก ํ์
์บ์คํ
์ ์ํํ ์ ์์ต๋๋ค. ํด๋น ์ ๋ณด๋ ๋ฐํ์์ ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์
๋๋ค.
๋ฐํ๋ ๊ฐ์ ๋ฐํ์ ๋ณํ์ ์ ์ฉํด์ผ ํ๋ ๊ฒฝ์ฐ .mapWith() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์กฐ๊ฑด๋ถ select
ํน์ ์กฐ๊ฑด์ ๋ฐ๋ผ ๋์ ์ ํ ๊ฐ์ฒด๋ฅผ ๊ฐ์ง ์ ์์ต๋๋ค:
async function selectUsers(withName: boolean) {
return db
.select({
id: users.id,
...(withName ? { name: users.name } : {}),
})
.from(users);
}
const users = await selectUsers(true);Distinct select (์ค๋ณต ์ ๊ฑฐ ์ ํ)
๋ฐ์ดํฐ์
์์ ๊ณ ์ ํ ํ๋ง ๊ฒ์ํ๋ ค๋ฉด .select() ๋์ .selectDistinct()๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค:
await db.selectDistinct().from(users).orderBy(users.id, users.name);
await db.selectDistinct({ id: users.id }).from(users).orderBy(users.id);select distinct "id", "name" from "users" order by "id", "name";
select distinct "id" from "users" order by "id";PostgreSQL์์๋ distinct on ์ ์ ์ฌ์ฉํ์ฌ ๊ณ ์ ํ ํ์ด ๊ฒฐ์ ๋๋ ๋ฐฉ์์ ์ง์ ํ ์๋ ์์ต๋๋ค:
distinct on ์ ์ PostgreSQL์์๋ง ์ง์๋ฉ๋๋ค.
await db.selectDistinctOn([users.id]).from(users).orderBy(users.id);
await db.selectDistinctOn([users.name], { name: users.name }).from(users).orderBy(users.name);select distinct on ("id") "id", "name" from "users" order by "id";
select distinct on ("name") "name" from "users" order by "name";Advanced select
TypeScript๋ฅผ ๊ธฐ๋ฐ์ผ๋ก Drizzle API๋ฅผ ์ฌ์ฉํ๋ฉด ๋ค์ํ๊ณ ์ ์ฐํ ๋ฐฉ์์ผ๋ก select ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
๊ณ ๊ธ ๋ถ๋ถ select์ ๋ํ ๋ฏธ๋ฆฌ๋ณด๊ธฐ์ ๋๋ค. ๋ ์์ธํ ๊ณ ๊ธ ์ฌ์ฉ ์์ ๋ ์ ์ฉ ๊ฐ์ด๋๋ฅผ ์ฐธ์กฐํ์ธ์.
import { getTableColumns, sql } from 'drizzle-orm';
await db.select({
...getTableColumns(posts),
titleLength: sql<number>`length(${posts.title})`,
}).from(posts);---
Filters
.where() ๋ฉ์๋์์ ํํฐ ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ์ฌ ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ํํฐ๋งํ ์ ์์ต๋๋ค:
import { eq, lt, gte, ne } from 'drizzle-orm';
await db.select().from(users).where(eq(users.id, 42));
await db.select().from(users).where(lt(users.id, 42));
await db.select().from(users).where(gte(users.id, 42));
await db.select().from(users).where(ne(users.id, 42));
...select "id", "name", "age" from "users" where "id" = 42;
select "id", "name", "age" from "users" where "id" < 42;
select "id", "name", "age" from "users" where "id" >= 42;
select "id", "name", "age" from "users" where "id" <> 42;๋ชจ๋ ํํฐ ์ฐ์ฐ์๋ sql ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๊ตฌํ๋ฉ๋๋ค.
์ด๋ฅผ ์ง์ ์ฌ์ฉํ์ฌ ์์์ SQL ํํฐ๋ฅผ ์์ฑํ๊ฑฐ๋ ์์ฒด ์ฐ์ฐ์๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
์๊ฐ์ ์ป์ผ๋ ค๋ฉด Drizzle์ด ์ ๊ณตํ๋ ์ฐ์ฐ์๊ฐ ์ด๋ป๊ฒ ๊ตฌํ๋๋์ง ํ์ธํ ์ ์์ต๋๋ค.
import { sql } from 'drizzle-orm';
function equals42(col: Column) {
return sql`${col} = 42`;
}
await db.select().from(users).where(sql`${users.id} < 42`);
await db.select().from(users).where(sql`${users.id} = 42`);
await db.select().from(users).where(equals42(users.id));
await db.select().from(users).where(sql`${users.id} >= 42`);
await db.select().from(users).where(sql`${users.id} <> 42`);
await db.select().from(users).where(sql`lower(${users.name}) = 'aaron'`);select "id", "name", "age" from "users" where 'id' < 42;
select "id", "name", "age" from "users" where 'id' = 42;
select "id", "name", "age" from "users" where 'id' = 42;
select "id", "name", "age" from "users" where 'id' >= 42;
select "id", "name", "age" from "users" where 'id' <> 42;
select "id", "name", "age" from "users" where lower("name") = 'aaron';ํํฐ ์ฐ์ฐ์์ sql ํจ์์ ์ ๊ณต๋๋ ๋ชจ๋ ๊ฐ์ ์๋์ผ๋ก ๋งค๊ฐ๋ณ์ํ๋ฉ๋๋ค.
์๋ฅผ ๋ค์ด, ๋ค์ ์ฟผ๋ฆฌ๋:
await db.select().from(users).where(eq(users.id, 42));๋ค์๊ณผ ๊ฐ์ด ๋ณํ๋ฉ๋๋ค:
select "id", "name", "age" from "users" where "id" = $1; -- params: [42]not ์ฐ์ฐ์๋ก ์กฐ๊ฑด ๋ฐ์ ํ๊ธฐ:
import { eq, not, sql } from 'drizzle-orm';
await db.select().from(users).where(not(eq(users.id, 42)));
await db.select().from(users).where(sql`not ${users.id} = 42`);select "id", "name", "age" from "users" where not ("id" = 42);
select "id", "name", "age" from "users" where not ("id" = 42);์คํค๋ง๋ฅผ ์์ ํ๊ฒ ๋ณ๊ฒฝํ๊ณ ํ ์ด๋ธ๊ณผ ์ปฌ๋ผ์ ์ด๋ฆ์ ๋ณ๊ฒฝํ ์ ์์ผ๋ฉฐ, ํ ํ๋ฆฟ ๋ณด๊ฐ ๋๋ถ์ ์ฟผ๋ฆฌ์ ์๋์ผ๋ก ๋ฐ์๋ฉ๋๋ค. ์ด๋ raw SQL์ ์์ฑํ ๋ ์ปฌ๋ผ์ด๋ ํ ์ด๋ธ ์ด๋ฆ์ ํ๋์ฝ๋ฉํ๋ ๊ฒ๊ณผ ๋์กฐ์ ์ ๋๋ค.
Combining filters
and()์ or() ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ์ฌ ํํฐ ์ฐ์ฐ์๋ฅผ ๋
ผ๋ฆฌ์ ์ผ๋ก ๊ฒฐํฉํ ์ ์์ต๋๋ค:
import { eq, and, sql } from 'drizzle-orm';
await db.select().from(users).where(
and(
eq(users.id, 42),
eq(users.name, 'Dan')
)
);
await db.select().from(users).where(sql`${users.id} = 42 and ${users.name} = 'Dan'`);select "id", "name", "age" from "users" where "id" = 42 and "name" = 'Dan';
select "id", "name", "age" from "users" where "id" = 42 and "name" = 'Dan';import { eq, or, sql } from 'drizzle-orm';
await db.select().from(users).where(
or(
eq(users.id, 42),
eq(users.name, 'Dan')
)
);
await db.select().from(users).where(sql`${users.id} = 42 or ${users.name} = 'Dan'`);select "id", "name", "age" from "users" where "id" = 42 or "name" = 'Dan';
select "id", "name", "age" from "users" where "id" = 42 or "name" = 'Dan';Advanced filters
TypeScript์ ๊ฒฐํฉํ์ฌ Drizzle API๋ ์ฟผ๋ฆฌ์์ ํํฐ๋ฅผ ๊ฒฐํฉํ๋ ๊ฐ๋ ฅํ๊ณ ์ ์ฐํ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค.
์กฐ๊ฑด๋ถ ํํฐ๋ง์ ๋ํ ๋ฏธ๋ฆฌ๋ณด๊ธฐ์ ๋๋ค. ๋ ์์ธํ ๊ณ ๊ธ ์ฌ์ฉ ์์ ๋ ์ ์ฉ ๊ฐ์ด๋๋ฅผ ์ฐธ์กฐํ์ธ์.
const searchPosts = async (term?: string) => {
await db
.select()
.from(posts)
.where(term ? ilike(posts.title, term) : undefined);
};
await searchPosts();
await searchPosts('AI');---
Limit & offset
.limit()๊ณผ .offset()์ ์ฌ์ฉํ์ฌ ์ฟผ๋ฆฌ์ limit๊ณผ offset ์ ์ ์ถ๊ฐํฉ๋๋ค - ์๋ฅผ ๋ค์ด ํ์ด์ง๋ค์ด์
์ ๊ตฌํํ๊ธฐ ์ํด:
await db.select().from(users).limit(10);
await db.select().from(users).limit(10).offset(10);select "id", "name", "age" from "users" limit 10;
select "id", "name", "age" from "users" limit 10 offset 10;Order By
.orderBy()๋ฅผ ์ฌ์ฉํ์ฌ ์ฟผ๋ฆฌ์ order by ์ ์ ์ถ๊ฐํ๊ณ ์ง์ ๋ ํ๋๋ก ๊ฒฐ๊ณผ๋ฅผ ์ ๋ ฌํฉ๋๋ค:
import { asc, desc } from 'drizzle-orm';
await db.select().from(users).orderBy(users.name);
await db.select().from(users).orderBy(desc(users.name));
// order by multiple fields
await db.select().from(users).orderBy(users.name, users.name2);
await db.select().from(users).orderBy(asc(users.name), desc(users.name2));select "id", "name", "age" from "users" order by "name";
select "id", "name", "age" from "users" order by "name" desc;
select "id", "name", "age" from "users" order by "name", "name2";
select "id", "name", "age" from "users" order by "name" asc, "name2" desc;Advanced pagination
TypeScript๋ฅผ ๊ธฐ๋ฐ์ผ๋ก Drizzle API๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฐ๋ฅํ ๋ชจ๋ SQL ํ์ด์ง๋ค์ด์ ๋ฐ ์ ๋ ฌ ๋ฐฉ์์ ๊ตฌํํ ์ ์์ต๋๋ค.
๊ณ ๊ธ ํ์ด์ง๋ค์ด์ ์ ๋ํ ๋ฏธ๋ฆฌ๋ณด๊ธฐ์ ๋๋ค. ๋ ์์ธํ ๊ณ ๊ธ ์ฌ์ฉ ์์ ๋ limit offset ํ์ด์ง๋ค์ด์ ๊ณผ ์ปค์ ํ์ด์ง๋ค์ด์ ๊ฐ์ด๋๋ฅผ ์ฐธ์กฐํ์ธ์.
await db
.select()
.from(users)
.orderBy(asc(users.id)) // order by is mandatory
.limit(4) // the number of rows to return
.offset(4); // the number of rows to skip---
WITH clause
with ์ ์ ์ฌ์ฉํ๋ฉด ๋ณต์กํ ์ฟผ๋ฆฌ๋ฅผ CTE(๊ณตํต ํ
์ด๋ธ ํํ์)๋ผ๊ณ ํ๋ ๋ ์์ ํ์ ์ฟผ๋ฆฌ๋ก ๋ถํ ํ์ฌ ๋จ์ํํ ์ ์์ต๋๋ค:
const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42)));
const result = await db.with(sq).select().from(sq);with sq as (select "id", "name", "age" from "users" where "id" = 42)
select "id", "name", "age" from sq;with ๋ด๋ถ์ insert, update, delete ๋ฌธ์ ์ ๊ณตํ ์๋ ์์ต๋๋ค
const sq = db.$with('sq').as(
db.insert(users).values({ name: 'John' }).returning(),
);
const result = await db.with(sq).select().from(sq);with "sq" as (insert into "users" ("id", "name") values (default, 'John') returning "id", "name")
select "id", "name" from "sq"const sq = db.$with('sq').as(
db.update(users).set({ age: 25 }).where(eq(users.name, 'John')).returning(),
);
const result = await db.with(sq).select().from(sq);with "sq" as (update "users" set "age" = 25 where "users"."name" = 'John' returning "id", "name", "age")
select "id", "name", "age" from "sq"const sq = db.$with('sq').as(
db.delete(users).where(eq(users.name, 'John')).returning(),
);
const result = await db.with(sq).select().from(sq);with "sq" as (delete from "users" where "users"."name" = $1 returning "id", "name", "age")
select "id", "name", "age" from "sq"CTE์์ ์์์ SQL ๊ฐ์ ํ๋๋ก ์ ํํ๊ณ ๋ค๋ฅธ CTE๋ ๋ฉ์ธ ์ฟผ๋ฆฌ์์ ์ฐธ์กฐํ๋ ค๋ฉด ๋ณ์นญ์ ์ถ๊ฐํด์ผ ํฉ๋๋ค:
const sq = db.$with('sq').as(db.select({
name: sql<string>`upper(${users.name})`.as('name'),
})
.from(users));
const result = await db.with(sq).select({ name: sq.name }).from(sq);๋ณ์นญ์ ์ ๊ณตํ์ง ์์ผ๋ฉด ํ๋ ํ์
์ด DrizzleTypeError๊ฐ ๋๋ฉฐ ๋ค๋ฅธ ์ฟผ๋ฆฌ์์ ์ฐธ์กฐํ ์ ์์ต๋๋ค.
ํ์
์๋ฌ๋ฅผ ๋ฌด์ํ๊ณ ์ฌ์ ํ ํ๋๋ฅผ ์ฌ์ฉํ๋ ค๊ณ ํ๋ฉด
๋ณ์นญ ์์ด๋ ํด๋น ํ๋๋ฅผ ์ฐธ์กฐํ ๋ฐฉ๋ฒ์ด ์๊ธฐ ๋๋ฌธ์ ๋ฐํ์ ์๋ฌ๊ฐ ๋ฐ์ํฉ๋๋ค.
Select from subquery
SQL๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ์๋ธ์ฟผ๋ฆฌ API๋ฅผ ์ฌ์ฉํ์ฌ ์ฟผ๋ฆฌ๋ฅผ ๋ค๋ฅธ ์ฟผ๋ฆฌ์ ํฌํจ์ํฌ ์ ์์ต๋๋ค:
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');
const result = await db.select().from(sq);select "id", "name", "age" from (select "id", "name", "age" from "users" where "id" = 42) "sq";์๋ธ์ฟผ๋ฆฌ๋ ํ ์ด๋ธ์ ์ฌ์ฉํ ์ ์๋ ๋ชจ๋ ๊ณณ์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ์กฐ์ธ์์:
const sq = db.select().from(users).where(eq(users.id, 42)).as('sq');
const result = await db.select().from(users).leftJoin(sq, eq(users.id, sq.id));select "users"."id", "users"."name", "users"."age", "sq"."id", "sq"."name", "sq"."age" from "users"
left join (select "id", "name", "age" from "users" where "id" = 42) "sq"
on "users"."id" = "sq"."id";---
Aggregations
Drizzle์ ์ฌ์ฉํ๋ฉด raw SQL์์ ํ๋ ๊ฒ๊ณผ ๋์ผํ๊ฒ
.groupBy()์ .having()์ผ๋ก ๊ทธ๋ฃนํ ๋ฐ ํํฐ๋งํ์ฌ sum, count, avg ๋ฑ๊ณผ ๊ฐ์ ํจ์๋ฅผ ์ฌ์ฉํ ์ง๊ณ๋ฅผ ์ํํ ์ ์์ต๋๋ค:
import { gt } from 'drizzle-orm';
await db.select({
age: users.age,
count: sql<number>`cast(count(${users.id}) as int)`,
})
.from(users)
.groupBy(users.age);
await db.select({
age: users.age,
count: sql<number>`cast(count(${users.id}) as int)`,
})
.from(users)
.groupBy(users.age)
.having(({ count }) => gt(count, 1));select "age", cast(count("id") as int)
from "users"
group by "age";
select "age", cast(count("id") as int)
from "users"
group by "age"
having cast(count("id") as int) > 1;cast(... as int)๋ count()๊ฐ PostgreSQL์์ bigint๋ฅผ, MySQL์์ decimal์ ๋ฐํํ๊ณ ์ด๋ค์ ์ซ์ ๋์ ๋ฌธ์์ด ๊ฐ์ผ๋ก ์ฒ๋ฆฌ๋๊ธฐ ๋๋ฌธ์ ํ์ํฉ๋๋ค.
๋๋ ๋ฐํ์์ ๊ฐ์ ์ซ์๋ก ์บ์คํ
ํ๊ธฐ ์ํด .mapWith(Number)๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
count ์ง๊ณ๊ฐ ํ์ํ ๊ฒฝ์ฐ - $count API ์ฌ์ฉ์ ๊ถ์ฅํฉ๋๋ค
Aggregations helpers
Drizzle์ ๋ํ๋ sql ํจ์ ์ธํธ๋ฅผ ์ ๊ณตํ๋ฏ๋ก ์ฑ์ ์ผ๋ฐ์ ์ธ ๊ฒฝ์ฐ์ ๋ํด
sql ํ
ํ๋ฆฟ์ ์์ฑํ ํ์๊ฐ ์์ต๋๋ค
์ง๊ณ ํจ์๋ SELECT ๋ฌธ์ GROUP BY ์ ๊ณผ ํจ๊ป ์์ฃผ ์ฌ์ฉ๋ฉ๋๋ค.
๋ฐ๋ผ์ ํ ์ฟผ๋ฆฌ์์ ์ง๊ณ ํจ์์ ๋ค๋ฅธ ์ปฌ๋ผ์ ์ ํํ๋ ๊ฒฝ์ฐ
.groupBy ์ ์ ๋ฐ๋์ ์ฌ์ฉํด์ผ ํฉ๋๋ค
count
expression์ ๊ฐ ๊ฐ์๋ฅผ ๋ฐํํฉ๋๋ค.
import { count } from 'drizzle-orm'
await db.select({ value: count() }).from(users);
await db.select({ value: count(users.id) }).from(users);select count("*") from "users";
select count("id") from "users";// It's equivalent to writing
await db.select({
value: sql`count('*'))`.mapWith(Number)
}).from(users);
await db.select({
value: sql`count(${users.id})`.mapWith(Number)
}).from(users);countDistinct
expression์ ์ค๋ณต๋์ง ์์ ๊ฐ์ ๊ฐ์๋ฅผ ๋ฐํํฉ๋๋ค.
import { countDistinct } from 'drizzle-orm'
await db.select({ value: countDistinct(users.id) }).from(users);select count(distinct "id") from "users";// It's equivalent to writing
await db.select({
value: sql`count(${users.id})`.mapWith(Number)
}).from(users);avg
expression์ ๋ชจ๋ null์ด ์๋ ๊ฐ์ ํ๊ท (์ฐ์ ํ๊ท )์ ๋ฐํํฉ๋๋ค.
import { avg } from 'drizzle-orm'
await db.select({ value: avg(users.id) }).from(users);select avg("id") from "users";// It's equivalent to writing
await db.select({
value: sql`avg(${users.id})`.mapWith(String)
}).from(users);avgDistinct
expression์ ๋ชจ๋ null์ด ์๋ ๊ฐ์ ํ๊ท (์ฐ์ ํ๊ท )์ ๋ฐํํฉ๋๋ค.
import { avgDistinct } from 'drizzle-orm'
await db.select({ value: avgDistinct(users.id) }).from(users);select avg(distinct "id") from "users";// It's equivalent to writing
await db.select({
value: sql`avg(distinct ${users.id})`.mapWith(String)
}).from(users);sum
expression์ ๋ชจ๋ null์ด ์๋ ๊ฐ์ ํฉ๊ณ๋ฅผ ๋ฐํํฉ๋๋ค.
import { sum } from 'drizzle-orm'
await db.select({ value: sum(users.id) }).from(users);select sum("id") from "users";// It's equivalent to writing
await db.select({
value: sql`sum(${users.id})`.mapWith(String)
}).from(users);sumDistinct
expression์ ๋ชจ๋ null์ด ์๋๊ณ ์ค๋ณต๋์ง ์์ ๊ฐ์ ํฉ๊ณ๋ฅผ ๋ฐํํฉ๋๋ค.
import { sumDistinct } from 'drizzle-orm'
await db.select({ value: sumDistinct(users.id) }).from(users);select sum(distinct "id") from "users";// It's equivalent to writing
await db.select({
value: sql`sum(distinct ${users.id})`.mapWith(String)
}).from(users);max
expression์ ์ต๋๊ฐ์ ๋ฐํํฉ๋๋ค.
import { max } from 'drizzle-orm'
await db.select({ value: max(users.id) }).from(users);select max("id") from "users";// It's equivalent to writing
await db.select({
value: sql`max(${expression})`.mapWith(users.id)
}).from(users);min
expression์ ์ต์๊ฐ์ ๋ฐํํฉ๋๋ค.
import { min } from 'drizzle-orm'
await db.select({ value: min(users.id) }).from(users);select min("id") from "users";// It's equivalent to writing
await db.select({
value: sql`min(${users.id})`.mapWith(users.id)
}).from(users);๋ ๊ณ ๊ธ ์์ :
const orders = sqliteTable('order', {
id: integer('id').primaryKey(),
orderDate: integer('order_date', { mode: 'timestamp' }).notNull(),
requiredDate: integer('required_date', { mode: 'timestamp' }).notNull(),
shippedDate: integer('shipped_date', { mode: 'timestamp' }),
shipVia: integer('ship_via').notNull(),
freight: numeric('freight').notNull(),
shipName: text('ship_name').notNull(),
shipCity: text('ship_city').notNull(),
shipRegion: text('ship_region'),
shipPostalCode: text('ship_postal_code'),
shipCountry: text('ship_country').notNull(),
customerId: text('customer_id').notNull(),
employeeId: integer('employee_id').notNull(),
});
const details = sqliteTable('order_detail', {
unitPrice: numeric('unit_price').notNull(),
quantity: integer('quantity').notNull(),
discount: numeric('discount').notNull(),
orderId: integer('order_id').notNull(),
productId: integer('product_id').notNull(),
});
db
.select({
id: orders.id,
shippedDate: orders.shippedDate,
shipName: orders.shipName,
shipCity: orders.shipCity,
shipCountry: orders.shipCountry,
productsCount: sql<number>`cast(count(${details.productId}) as int)`,
quantitySum: sql<number>`sum(${details.quantity})`,
totalPrice: sql<number>`sum(${details.quantity} * ${details.unitPrice})`,
})
.from(orders)
.leftJoin(details, eq(orders.id, details.orderId))
.groupBy(orders.id)
.orderBy(asc(orders.id))
.all();$count
db.$count()๋ count(*)์ ์ ํธ๋ฆฌํฐ ๋ํผ๋ก, ๊ทธ๋๋ก ์ฌ์ฉํ๊ฑฐ๋ ์๋ธ์ฟผ๋ฆฌ๋ก ์ฌ์ฉํ ์ ์๋ ๋งค์ฐ ์ ์ฐํ ์ฐ์ฐ์์
๋๋ค. ์์ธํ ๋ด์ฉ์ GitHub ํ ๋ก ์ ์ฐธ์กฐํ์ธ์.
const count = await db.$count(users);
// ^? number
const count = await db.$count(users, eq(users.name, "Dan")); // ํํฐ์ ํจ๊ป ์๋select count(*) from "users";
select count(*) from "users" where "name" = 'Dan';์๋ธ์ฟผ๋ฆฌ์์ ํนํ ์ ์ฉํฉ๋๋ค:
const users = await db.select({
...users,
postsCount: db.$count(posts, eq(posts.authorId, users.id)),
}).from(users);๊ด๊ณํ ์ฟผ๋ฆฌ์ ํจ๊ป ์ฌ์ฉํ๋ ์์
const users = await db.query.users.findMany({
extras: {
postsCount: db.$count(posts, eq(posts.authorId, users.id)),
},
});---
Iterator
์ฟผ๋ฆฌ์์ ๋งค์ฐ ๋ง์ ์์ ํ์ ๋ฐํํด์ผ ํ๊ณ ๋ชจ๋ ํ์ ๋ฉ๋ชจ๋ฆฌ์ ๋ก๋ํ๊ณ ์ถ์ง ์์ ๊ฒฝ์ฐ .iterator()๋ฅผ ์ฌ์ฉํ์ฌ ์ฟผ๋ฆฌ๋ฅผ ๋น๋๊ธฐ ์ดํฐ๋ ์ดํฐ๋ก ๋ณํํ ์ ์์ต๋๋ค:
const iterator = await db.select().from(users).iterator();
for await (const row of iterator) {
console.log(row);
}prepared statement์๋ ์๋ํฉ๋๋ค:
const query = await db.select().from(users).prepare();
const iterator = await query.iterator();
for await (const row of iterator) {
console.log(row);
}---
Use Index
USE INDEX ํํธ๋ ์ฟผ๋ฆฌ๋ฅผ ์ฒ๋ฆฌํ ๋ ๊ณ ๋ คํ ์ธ๋ฑ์ค๋ฅผ ์ตํฐ๋ง์ด์ ์ ์ ์ํฉ๋๋ค. ์ตํฐ๋ง์ด์ ๋ ์ด๋ฌํ ์ธ๋ฑ์ค๋ฅผ ๊ฐ์ ๋ก ์ฌ์ฉํ์ง๋ ์์ง๋ง ์ ํฉํ ๊ฒฝ์ฐ ์ฐ์ ์์๋ฅผ ๋ถ์ฌํฉ๋๋ค.
export const users = mysqlTable('users', {
id: int('id').primaryKey(),
name: varchar('name', { length: 100 }).notNull(),
}, () => [usersTableNameIndex]);
const usersTableNameIndex = index('users_name_index').on(users.name);
await db.select()
.from(users, { useIndex: usersTableNameIndex })
.where(eq(users.name, 'David'));์ํ๋ ์กฐ์ธ์์๋ ์ด ์ต์ ์ ์ฌ์ฉํ ์ ์์ต๋๋ค
await db.select()
.from(users)
.leftJoin(posts, eq(posts.userId, users.id), { useIndex: usersTableNameIndex })
.where(eq(users.name, 'David'));Ignore Index
IGNORE INDEX ํํธ๋ ์ฟผ๋ฆฌ์ ๋ํด ํน์ ์ธ๋ฑ์ค๋ฅผ ์ฌ์ฉํ์ง ์๋๋ก ์ตํฐ๋ง์ด์ ์ ์๋ฆฝ๋๋ค. MySQL์ ๋ค๋ฅธ ๋ชจ๋ ์ธ๋ฑ์ค๋ฅผ ๊ณ ๋ คํ๊ฑฐ๋(์๋ ๊ฒฝ์ฐ) ํ์ํ ๊ฒฝ์ฐ ์ ์ฒด ํ
์ด๋ธ ์ค์บ์ ์ํํฉ๋๋ค.
export const users = mysqlTable('users', {
id: int('id').primaryKey(),
name: varchar('name', { length: 100 }).notNull(),
}, () => [usersTableNameIndex]);
const usersTableNameIndex = index('users_name_index').on(users.name);
await db.select()
.from(users, { ignoreIndex: usersTableNameIndex })
.where(eq(users.name, 'David'));์ํ๋ ์กฐ์ธ์์๋ ์ด ์ต์ ์ ์ฌ์ฉํ ์ ์์ต๋๋ค
await db.select()
.from(users)
.leftJoin(posts, eq(posts.userId, users.id), { useIndex: usersTableNameIndex })
.where(eq(users.name, 'David'));Force Index
FORCE INDEX ํํธ๋ ์ฟผ๋ฆฌ์ ๋ํด ์ง์ ๋ ์ธ๋ฑ์ค๋ฅผ ๊ฐ์ ๋ก ์ฌ์ฉํ๋๋ก ์ตํฐ๋ง์ด์ ์ ์ง์ํฉ๋๋ค. ์ง์ ๋ ์ธ๋ฑ์ค๋ฅผ ์ฌ์ฉํ ์ ์๋ ๊ฒฝ์ฐ MySQL์ ๋ค๋ฅธ ์ธ๋ฑ์ค๋ก ํด๋ฐฑํ์ง ์์ผ๋ฉฐ ๋์ ์ ์ฒด ํ
์ด๋ธ ์ค์บ์ ์ํํ ์ ์์ต๋๋ค.
export const users = mysqlTable('users', {
id: int('id').primaryKey(),
name: varchar('name', { length: 100 }).notNull(),
}, () => [usersTableNameIndex]);
const usersTableNameIndex = index('users_name_index').on(users.name);
await db.select()
.from(users, { forceIndex: usersTableNameIndex })
.where(eq(users.name, 'David'));์ํ๋ ์กฐ์ธ์์๋ ์ด ์ต์ ์ ์ฌ์ฉํ ์ ์์ต๋๋ค
await db.select()
.from(users)
.leftJoin(posts, eq(posts.userId, users.id), { useIndex: usersTableNameIndex })
.where(eq(users.name, 'David'));