본문 바로가기

[IT/Programming]/Algorithm/Database

prisma with PostgreSQL - cursor based pagination

728x90
반응형
# prisma with PostgreSQL - cursor based pagination 페이지값을 넘겨주어 글들을 가져오는 offset based pagination 과는 달리 넘겨준 마지막 아이템을 이용해서 pagination을 하는 방식. Offset based 에 비해 장점을 많이 가지고 있어서 사용법을 정리할 겸 포스팅. ## PH
  • 2024-09-25 : First posting.
## Cursor based pagination 의 장단점 장점
1. 데이터 양이 커져도 영향을 적게 받는다. (@@index 필수적) 2. 데이터가 중간에 만들어지거나 사라져도 영향을 적게 받는다. (Cursor 에 해당하는 entity 가 사라지면 안됨.)
단점
1. 키가 정렬이되 있는 숫자여야 한다. (@@index 필수적) 2. 특정 페이지로 이동 할 수 없다. (이건 어쩔 수 없이 offset based 로 가야 함.)
## 예제 ```[.scrollable.lang-js] app.get("/users/:userId/productComments", asyncHandler(async (req, res) => { const { userId } = req.params; const { cursor, limit = 10, sort = "recent" } = req.query; let orderBy; switch (sort) { case "oldest": orderBy = { updatedAt: "asc" }; break; case "recent": default: orderBy = { updatedAt: "desc" }; } const productComments = await prisma.productComment.findMany({ orderBy, where: { commenterId: userId, }, cursor: cursor ? { id: cursor, }: undefined, skip: cursor ? 1 : 0, take: parseInt(limit), select: { id: true, content: true, createdAt: true, updatedAt: true, }, }); res.send(productComments); })); app.get("/users/:userId/articleComments", asyncHandler(async (req, res) => { const { userId } = req.params; const { cursor, limit = 10, sort = "recent" } = req.query; let orderBy; switch (sort) { case "oldest": orderBy = { updatedAt: "asc" }; break; case "recent": default: orderBy = { updatedAt: "desc" }; } const articleComments = await prisma.articleComment.findMany({ orderBy, where: { commenterId: userId, }, cursor: cursor ? { id: cursor, } : undefined, skip: cursor ? 1 : 0, take: parseInt(limit), select: { id: true, content: true, createdAt: true, updatedAt: true, }, }); res.send(articleComments); })); ```/ Cursor 가 있을 경우 skip: 1, 없을 경우 skip: 0.
orderBy 설정하고 where 로 특정 commenter 로 한정한 뒤, cursor 가 있을 경우만 cursor: { id: cursor } 형태로 전달.
### Schema ```[.scrollable] model ProductComment { id String @id @default(uuid()) content String productId String? product Product? @relation(fields: [productId], references: [id], onDelete: SetNull) commenterId String? commenter User? @relation(fields: [commenterId], references: [id], onDelete: SetNull) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([commenterId, updatedAt(sort: Desc)]) } model ArticleComment { id String @id @default(uuid()) content String articleId String? article Article? @relation(fields: [articleId], references: [id], onDelete: SetNull) commenterId String? commenter User? @relation(fields: [commenterId], references: [id], onDelete: SetNull) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([commenterId, updatedAt(sort: Desc)]) } ```/ 빠른 검색을 위해 @@index([commenterId, updatedAt(sort: Desc)]) 추가. ## RRA
  1. https://www.prisma.io/docs/orm/prisma-client/queries/pagination
728x90
반응형