앞으로 등장할 코드에서 prisma 변수는 const prisma = new PrismaClient() 를 의미합니다.
mysql 사용 기준으로 작성되어 몇몇 기능 및 지원에 대한 내용이 없을 수 있습니다.
Generated Type
prisma generate 명령어 실행 시 기본적으로 각 model type 이 생성되고 query 의 옵션, 필터, 입력값, 결과값 등등 여러가지 관련 type 또한 생성되어 필요한 경우 import 하여 사용할 수 있습니다.
example
// ex) UserCreateInput
type UserCreateInput = {
name: string;
email: string;
};
// generated type 사용 예시
import { Prisma } from "@prisma/client";
let user: Prisma.UserCreateInput
레코드 생성 (Create)
create() : 단일 레코드 생성 후 해당 레코드 데이터 반환
const prisma = new PrismaClient()
const user = await prisma.user.create({
// 생성 시 필요한 데이터
data: {
email: 'elsa@prisma.io',
name: 'Elsa Prisma',
},
})
createMany() : 여러 레코드 생성 후 해당 레코드 개수 반환
// createMany 의 값은 { count: 3 }
const createMany = await prisma.user.createMany({
data: [
{ name: 'Bob', email: 'bob@prisma.io' },
{ name: 'Bobo', email: 'bob@prisma.io' }, // 이메일이 unique key 라면 bob@prisma.io' 는 중복된 unique key
{ name: 'Yewande', email: 'yewande@prisma.io' },
],
skipDuplicates: true, // Skip 'Bobo'
})
createManyAndReturn() : 여러 레코드 생성 후 해당 레코드 데이터 목록 반환
const users = await prisma.user.createManyAndReturn({
data: [
{ name: 'Alice', email: 'alice@prisma.io' },
{ name: 'Bob', email: 'bob@prisma.io' },
],
})
// users results:
[
{
id: 22,
name: 'Alice',
email: 'alice@prisma.io',
}, {
id: 23,
name: 'Bob',
email: 'bob@prisma.io',
}
]
레코드 읽기 (Read)
findUnique() : ID 또는 unique identifier 로 특정된 레코드 반환
// By unique identifier
const user = await prisma.user.findUnique({
where: { email: 'elsa@prisma.io' },
})
// By ID
const user = await prisma.user.findUnique({
where: { id: 99 },
})
findMany() : 특정 기준에 해당되는 레코드 목록 반환
// 전체 레코드 반환
const users = await prisma.user.findMany()
// 필터링된 레코드 목록 반환
const users = await prisma.user.findMany({
where: {
email: { endsWith: 'prisma.io' },
},
})
findFirst() : 특정 기준과 일치하는 첫 번째 레코드 반환
// 좋아요가 100개 이상인 게시물이 하나 이상 있는 ID 기준 내림차순 첫 번째 사용자를 반환
const findUser = await prisma.user.findFirst({
where: {
posts: {
some: {
likes: { gt: 100 },
},
},
},
orderBy: { id: 'desc' },
})
레코드 변경 (Update)
update() : 단일 레코드 변경 후 해당 레코드 데이터 반환
const updateUser = await prisma.user.update({
where: { email: 'viola@prisma.io' },
data: { name: 'Viola the Magnificent' },
})
updateMany() : 여러 레코드 변경 후 해당 레코드 개수 반환
// email 에 prisma.io 를 포함하는 모든 사용자 레코드를 업데이트
// updateUsersCount 의 형식은 { count: number }
const updateUsersCount = await prisma.user.updateMany({
where: {
email: { contains: 'prisma.io' },
},
data: { role: 'ADMIN' },
})
updateManyAndReturn() : 여러 레코드 변경 후 해당 레코드 데이터 반환
// email 에 prisma.io 를 포함하는 모든 사용자 레코드를 업데이트
const users = await prisma.user.updateManyAndReturn({
where: {
email: { contains: 'prisma.io' }
},
data: { role: 'ADMIN' }
})
upsert() : 레코드를 변경하거나 해당 레코드가 없는 경우 해당 레코드를 만듭니다.
const upsertUser = await prisma.user.upsert({
where: { email: 'viola@prisma.io' },
update: { name: 'Viola the Magnificent' },
create: {
email: 'viola@prisma.io',
name: 'Viola the Magnificent',
},
})
레코드 삭제 (Delete)
delete() : 단일 레코드 삭제 후 해당 레코드 데이터 반환
const deleteUser = await prisma.user.delete({
where: { email: 'bert@prisma.io' },
})
deleteMany() : 여러 레코드 삭제 후 해당 레코드 개수 반환
const deleteUsersCount = await prisma.user.deleteMany({
where: {
email: { contains: 'prisma.io' },
},
})
// 전체 레코드 삭제
const deleteAllUsersCount = await prisma.user.deleteMany({})
Query Option
select : 지정한 필드 하위 집합을 반환
const user = await prisma.user.findUnique({
where: {
email: 'emma@prisma.io',
},
// 이메일 및 이름 필드만 반환
select: {
email: true,
name: true,
},
})
// 중첩 select
const usersWithPostTitles = await prisma.user.findFirst({
select: {
name: true,
posts: {
select: { title: true },
},
},
})
// usersWithPostTitles results:
{
"name":"Sabelle",
"posts":[
{ "title":"Getting started with Azure Functions" },
{ "title":"All about databases" }
]
}
omit: 일부 필드 하위 집합을 제외하고 반환
const users = await prisma.user.findFirst({
// 전체 데이터 중 password 만 제외하고 반환
omit: { password: true }
})
include : 관계된 필드 내용을 포함해서 반환
const user = await prisma.user.findFirst({
include: { posts: true },
})
// user results example:
{
id: 19,
name: null,
email: 'emma@prisma.io',
posts: [
{
id: 20,
...
},
]
}
// include 중첩 사용
const user = await prisma.user.findFirst({
include: {
posts: {
include: {
categories: true,
},
},
},
})
// user results example:
{
id: 19,
name: null,
email: 'emma@prisma.io',
posts: [
{
id: 20,
categories: [
{
id: 3,
name: "Easy cooking"
},
]
...
},
]
}
(주의 사항)
1. include 내부에 select 사용 가능하지만, select 내부에 include 는 불가능
기본적으로 select는 특정 컬럼(필드)만 선택하는 역할을 하며, 이는 데이터베이스에서 SELECT 쿼리로 특정 데이터만 가져오는 작업입니다. 반면, include는 관계 데이터를 함께 가져오는 역할을 하며, 이는 SQL에서 JOIN 을 사용하여 두 개 이상의 테이블을 연결하고 데이터를 조합하는 방식과 유사합니다.
이 두 기능을 종합적으로 고려했을 때, include(JOIN) 로 확장된 데이터는 다시 select를 통해 필터링하거나 선택할 수 있습니다. 그러나 select(SELECT)로 선택된 특정 필드를 다시 **include를 통해 확장하는 것은 부적절한 방식입니다. 왜냐하면 **select 는 이미 필요한 필드를 제한하는 역할을 하고, 관계를 확장하는 include와는 본질적으로 다른 작업이기 때문입니다.
2. include 와 select 는 같은 레벨에서 사용 불가
일반적으로 db 에서는 JOIN 과 SELECT 같이 사용 가능하지만 prisma 는 select와 include 두 작업이 서로 충돌할 수 있기에 같은 레벨에서 함께 사용하는 것을 허용하지 않습니다.
※ prisma 상에서 include(JOIN) 하여 통합된 일부 데이터만 select(SELECT)싶다면 차라리 쿼리를 분리하는 방식을 고려해볼 수 있겠다.
// ❌ prisma 에서 작동하지 않는 잘못된 코드
const user = await prisma.user.findUnique({
where: { id: 1 },
select: {
email: true, // 이메일만 선택
posts: {
select: { title: true }, // 포스트 제목만 선택
},
},
include: { posts: true }, // posts 관계 데이터를 포함하려는 시도
});
// ✅ 쿼리를 분리한 다른 패턴 코드
const [user, posts] = await Promise.all([
prisma.user.findUnique({
where: { id: 1 },
select: { email: true }, // 이메일만 선택
}),
prisma.post.findMany({
where: { userId: 1 },
select: { title: true }, // 포스트 제목만 선택
}),
]);
const result = {
...user,
posts,
}
다음 포스트에서 이어집니다.
참고
https://www.prisma.io/docs/orm/prisma-client/queries/crud
https://www.prisma.io/docs/orm/prisma-client/queries/select-fields
https://www.prisma.io/docs/orm/prisma-client/queries/relation-queries
'Prisma' 카테고리의 다른 글
[Prisma] 6. Pagination & Aggregation (0) | 2025.01.18 |
---|---|
[Prisma] 5. Nested Queries (0) | 2025.01.17 |
[Prisma] 4. query filtering & sorting (0) | 2025.01.17 |
[Prisma] 2. Prisma Model 디테일 (0) | 2025.01.12 |
[Prisma] 1. Prisma 란 무엇인가? (0) | 2025.01.11 |