내일배움캠프 Node.js 트랙 25일차
Prisma에서 자주 쓰는 문법 정리하기
들어가기에 앞서…
나는 지난 사전 캠프 기간 동안 MySQL을 공부하고 여러 예제를 풀었던 적이 있다. 즉, 내게 익숙한 RDBMS 형태는 사실 아래와 같았다.
CREATE DATABASE step3;
USE step3;
CREATE TABLE orders(
id INT PRIMARY KEY,
customer_id INT,
product_id INT,
amount INT,
shipping_fee INT,
order_date DATE
);
INSERT INTO orders (id, customer_id, product_id, amount, shipping_fee) VALUES
(1, 719,1, 3, 50000, '2023-11-01'),
(2, 131, 2, 1, 10000, '2023-11-02'),
(3, 65, 4, 1, 20000, '2023-11-05'),
(4, 1008, 3, 2, 25000, '2023-11-05'),
(5, 356, 1, 1, 15000, '2023-11-09');
CLI 환경에서 SQL 문제를 풀던 모습
이번 노드 숙련 기간에 접어들고 Raw Query 챕터의 강의를 들을 때만 해도 내가 앞으로 쓸 언어는 위와 같은 모습일 거라고 의심치 않았다. 그런데, 정작 프로젝트(아이템 시뮬레이터)를 진행하는 동안 가장 많이 쓰게 된 건 MySQL이 아니었다. prisma라는 이름을 가진 새로운 DB 관리 모듈이었다.
Prisma가 무엇이길래?
Prisma는 ORM(Object Relational Mapping) 도구이다. 여기서 또 머리가 아파온다. ORM…이 뭐지? ORM을 이해하기 위해선 일단 MySQL을 쓰던 시절로 돌아가 기억을 되살려보자. CLI 창에 적어내리던 저 무수한 코드들. 아무것도 몰랐던 시절엔 JS랑 비슷해 보였을지 몰라도 이제는 전혀 다르다는 걸 알 수 있을 터다.
즉, 둘은 서로 다른 언어다. 한국인을 대상으로 한국어와 러시아어를 혼용하면서 뜻이 완벽하게 통하기를 바란다고 상상해보자. 그건 뭔가 이상하다. (노어에 대해 잘은 모르지만) 둘은 아마 어순도 다를 것이고, 관사나 조사가 가지는 규칙도 다를 것이다. JS에서 SQL이 쓰는 문법을 그대로 쓰는 건 다소 어리석은 일이란 뜻이다. JS에 익숙해진 우리로선, SQL의 SELECT 문법은 너무 평면적이고 과하게 공간을 차지하는 것으로 보일 수밖에 없다.
그래서 필요한 것이 ORM이다. ORM(Object-Relational Mapping)은 객체 지향 프로그래밍 언어를 사용하여 호환되지 않는 유형의 시스템 간에 데이터를 변환하는 프로그래밍 기술이다. 이는 개발자가 객체 지향 프로그래밍에 더 집중할 수 있게 해주며, 데이터베이스 설계와 비즈니스 로직 사이의 간극을 줄여준다.
더 간결한 코드를 쓸 수 있으며, SQL Injection을 방지하는 등 보안성까지 두루 갖추었으니 쓰지 않을 이유가 없다.(사실은 단점도 많은데 극적인 분위기를 위해 그런 셈 치겠다.)
각설하고, Prisma의 주요 기능과 문법을 정리해보자.
1. 데이터 조회
findUnique
단일 레코드를 조회할 수 있다. id나 사용자의 email처럼 고유한 값을 조회할 때 제격이다.
따라서, where
조건에 반드시 고유한 값을 넣어야 오류가 나지 않는다.
const user = await prisma.user.findUnique({
where: {
id: 1,
},
});
findMany
다중 레코드 조회할 때 사용한다. 조건, 정렬, 페이징이 가능하다.
const users = await prisma.user.findMany({
where: {
age: { gt: 18 },
},
orderBy: {
createdAt: 'desc',
},
take: 10, // 상위 10개 레코드 가져오기
skip: 5, // 첫 5개 레코드 건너뛰기
});
findFirst
findMany
와 비슷하지만, 첫 번째 레코드만 반환한다.
const firstUser = await prisma.user.findFirst({
where: {
isActive: true,
},
});
2. 데이터 생성
create
단일 레코드를 생성한다.
const newUser = await prisma.user.create({
data: {
name: 'John Doe',
email: 'john@example.com',
age: 25,
},
});
createMany
다중 레코드를 생성한다.
await prisma.user.createMany({
data: [
{ name: 'Alice', email: 'alice@example.com' },
{ name: 'Bob', email: 'bob@example.com' },
],
});
3. 데이터 업데이트
update
단일 레코드를 업데이트한다. where
조건에 고유 값이 필요하다.
const updatedUser = await prisma.user.update({
where: {
id: 1,
},
data: {
email: 'new-email@example.com',
},
});
updateMany
다중 레코드를 업데이트한다. where
조건을 만족하는 모든 레코드 업데이트한다.
await prisma.user.updateMany({
where: {
isActive: false,
},
data: {
isActive: true,
},
});
4. 데이터 삭제
delete
단일 레코드 삭제한다. where
조건에 고유 값 필요하다.
await prisma.user.delete({
where: {
id: 1,
},
});
deleteMany
다중 레코드 삭제한다.
await prisma.user.deleteMany({
where: {
age: { lt: 18 },
},
});
5. 업서트 (Upsert)
존재하면 업데이트, 없으면 생성한다.
const upsertedUser = await prisma.user.upsert({
where: {
email: 'john@example.com',
},
update: {
name: 'John Doe Updated',
},
create: {
name: 'John Doe',
email: 'john@example.com',
age: 30,
},
});
6. 트랜잭션
$transaction
여러 데이터베이스 작업을 하나의 트랜잭션으로 실행해준다. 무슨 뜻이냐 하면 트랜잭션 내부의 과정들은 원자성을 띄어서 하나의 시퀀스로 완료가 되어야지만 커밋이 된다는 의미다. 하나라도 실패하면 롤백 지점으로 복구된다.(오류는 덤)
await prisma.$transaction(async (tx) => {
await tx.user.create({
data: { name: 'Alice' },
});
await tx.post.create({
data: { title: 'Hello World', authorId: 1 },
});
});
7. Raw SQL
queryRaw
SQL 쿼리를 직접 실행 (데이터 조회).
const result = await prisma.$queryRaw`SELECT * FROM User WHERE age > ${18}`;
executeRaw
SQL 쿼리를 직접 실행 (데이터 수정, 삭제).
await prisma.$executeRaw`DELETE FROM User WHERE isActive = false`;
8. 필터 조건
비교 연산자
where: {
age: { gt: 18 }, // greater than
age: { gte: 18 }, // greater than or equal
age: { lt: 30 }, // less than
age: { lte: 30 }, // less than or equal
name: { contains: 'J' }, // 문자열 포함
}
논리 연산자
where: {
AND: [{ isActive: true }, { age: { gt: 18 } }],
OR: [{ isActive: false }, { age: { lt: 18 } }],
}
배열 조건
where: {
id: { in: [1, 2, 3] },
}
9. 릴레이션 (Relation) 데이터 처리
include
릴레이션 데이터를 포함해 조회.
const userWithPosts = await prisma.user.findUnique({
where: { id: 1 },
include: {
posts: true, // Post 모델 데이터 포함
},
});
connect
릴레이션 데이터 연결.
await prisma.post.create({
data: {
title: 'Hello World',
author: {
connect: { id: 1 }, // User의 id가 1인 레코드와 연결
},
},
});
disconnect
릴레이션 데이터 연결 해제.
await prisma.post.update({
where: { id: 1 },
data: {
author: {
disconnect: true,
},
},
});
'개발일지 > TIL(Today I Learned)' 카테고리의 다른 글
2024-12-04 (0) | 2024.12.04 |
---|---|
2024-12-03 (1) | 2024.12.03 |
2024-11-29 (0) | 2024.11.29 |
2024-11-28 (2) | 2024.11.28 |
2024-11-27 (1) | 2024.11.27 |
댓글