본문 바로가기
Prisma

[Prisma] 6. Pagination & Aggregation

by spare8433 2025. 1. 18.
앞으로 등장할 코드에서 prisma 변수는 const prisma = new PrismaClient() 를 의미합니다.
mysql 사용 기준으로 작성되어 몇몇 기능 및 지원에 대한 내용이 없을 수 있습니다.

 

Pagination

Prisma Clientoffset paginationcursor-based pagination 을 모두 지원합니다.



1. Offset Pagination

데이터베이스에서 데이터를 페이징할 때시작 지점(offset) 과 가져올 데이터 수(limit)를 기반으로 데이터를 가져오는 방식입니다. 주로 SQL 쿼리의 OFFSET 과 LIMIT을 사용합니다.

 

대부분의 데이터베이스가 LIMIT 과 OFFSET을 지원하며, 로직도 간단하게 구현할 수 있는 반면 OFFSET 값이 커질수록 성능 저하가 발생(데이터베이스는 OFFSET 만큼 데이터를 스캔한 뒤 버리고 나머지를 반환 )합니다.



const results = await prisma.post.findMany({
  skip: 40,
  take: 10,
  where: {
    email: { contains: 'prisma.io' },
  },
  orderBy:  { title:  'desc' },
})





2. Cursor-Based Pagination

데이터의 고유 식별자(예: id 또는 created_at 필드)를 기준으로 데이터를 페이징하는 방식입니다. 클라이언트는 현재 위치(cursor)를 기준으로 다음 데이터를 가져옵니다.

 

무한 스크롤을 구현할 때 유용합니다.



주의 사항

  • 무조건 커서를 기준으로 정렬 해야 하며 커서는 고유하고 순차적인 열이어야 합니다.
  • 커서만 사용하여 특정 페이지로 이동 불가합니다



const queryResults = await prisma.post.findMany({
  take: 4,
   skip: 1, // Skip the cursor
  cursor: { id: ... }  // 특정 id 를 기준으로 시작 위치를 지정
  where: {
    title: { contains: "Prisma" }, // Optional filter
  },
  orderBy: { id: "asc" },
})






aggregate()

여러 레코드를 집계(Aggregation)하는 기능을 제공하는 Prisma Client의 메서드입니다. 데이터의 요약된 값을 계산하는 데 사용되며, 예를 들어 sum, average, min, max, count 등의 연산을 포함합니다.

 

  • _count: 특정 조건에 맞는 레코드의 개수를 셈.
  • _sum: 특정 필드의 값들을 더한 값을 구함.
  • _avg: 특정 필드의 값들의 평균을 구함.
  • _min: 특정 필드에서 최소 값을 구함.
  • _max: 특정 필드에서 최대 값을 구함



const aggregations = await prisma.user.aggregate({
  _avg: { age: true },
  where: { ... },
  orderBy: { ... },
  take: 5, // 목록에서 반환해야 하는 객체의 수를 지정
  skip: 0, // 건너뛸 객체의 수를 지정
  cursor: { id: 10, },// 'id'가 10인 레코드를 기준으로 이후의 데이터를 가져옴
  _avg: { age: true },  
  _count: { ... },
  _sum: { ... },
  _min: { ... },
  _max: { ... },
})

console.log('Average age:' + aggregations._avg.id)






groupBy()

wherehaving의 두 가지 수준의 필터링을 지원

 

where 를 사용하여 그룹화하기 전에 모든 레코드를 필터링하며, having 을 사용하여 필드의 합계나 평균과 같은 집계 값으로 전체 그룹을 필터링



const groupUsers =  await prisma.user.groupBy({
  by: ['country'],
  where: { ... },
  having: {
    profileViews: {
      _avg: { gt: 100 },
    },
  },
  orderBy: { ... },
  take: 5, // 목록에서 반환해야 하는 객체의 수를 지정
  skip: 0, // 건너뛸 객체의 수를 지정
  cursor: { id: 10, },// 'id'가 10인 레코드를 기준으로 이후의 데이터를 가져옴
  _avg: { ... },  
  _count: { ... },
  _sum: { ... },
  _min: { ... },
  _max: { ... },
})






count()

사용하여 레코드 수 또는 null이 아닌 필드 값을 계산



const userCount = await prisma.user.count({
  where: { ... },
  orderBy: { ... },
  take: 5, // 목록에서 반환해야 하는 객체의 수를 지정
  skip: 0, // 건너뛸 객체의 수를 지정
  cursor: { id: 10, },// 'id'가 10인 레코드를 기준으로 이후의 데이터를 가져옴
})





_count

관계의 수를 반환하며 최상위 include 또는 select 내부에서 사용할 수 있습니다.



const usersWithIncludeCount = await prisma.user.findMany({
  include: {
    _count: {
      select: { posts: true },
    },
  },
})

// usersWithIncludeCount results :
{ id: 1, _count: { posts: 3 } },
{ id: 2, _count: { posts: 2 } },
{ id: 3, _count: { posts: 2 } },
{ id: 4, _count: { posts: 0 } },
{ id: 5, _count: { posts: 0 } }


const usersWithSelectCount = await prisma.user.findMany({
  select: {
    _count: {
      select: { posts: true },
    },
  },
})

// usersWithSelectCount results
{  
  _count:  { posts:  3 }  
}


// _count 하위에서 select 로 관계수 필터링
await prisma.user.findMany({
  select: {
    _count: {
      select: {
        posts: { where: { title: 'Hello!' } },
      },
    },
  },
})






참고

https://www.prisma.io/docs/orm/prisma-client/queries/pagination
https://www.prisma.io/docs/orm/prisma-client/queries/aggregation-grouping-summarizing