Pagination(페이징)은 데이터베이스에서 대량의 데이터를 효율적으로 처리하고 사용자에게 보여주기 위한 방법입니다.
주요 특징은 다음과 같습니다.
데이터셋을 여러 페이지로 나누어, 한 번에 너무 많은 데이터를 로드하지 않고도 필요한 정보에 접근할 수 있게 합니다.
이는 사용자 경험을 개선하고, 시스템의 메모리 사용을 줄이는 데 도움이 됩니다.
사용자가 페이지 간 쉽게 이동할 수 있도록 하는 네비게이션 요소
(예: 이전, 다음, 첫 페이지, 마지막 페이지 링크)를 제공합니다.
페이지에 표시되는 데이터의 형식과 구조를 일관되게 유지하여
사용자에게 친숙한 경험을 제공합니다.
사용자가 현재 위치한 페이지를 기억하고, 이전 상태로 돌아갈 수 있도록 합니다.
이는 특히 검색 및 필터링을 수행하는 경우 유용합니다.
데이터베이스에서 필요한 데이터만 로드하여 성능을 향상시킵니다.
전체 데이터를 한 번에 가져오는 것보다 페이지 단위로 요청하여 서버 및 클라이언트 측의 부하를 줄일 수 있습니다.
Nest.js에서의 Pagination을 구현하기 위한 간단한 예제 코드입니다.
다음은 GET /users?page=1&limit=10 형식으로 사용자 목록을 페이지네이션하여 가져오는 API의 예시입니다.
import { IsInt, IsNotEmpty } from 'class-validator';
export class PaginationDto {
@IsInt()
@IsNotEmpty()
page: number;
@IsInt()
@IsNotEmpty()
limit: number;
}
import { Injectable } from '@nestjs/common';
import { PaginationDto } from './user.dto';
@Injectable()
export class UserService {
private readonly users = [ /* ... User Data ... */ ];
findAll(paginationDto: PaginationDto) {
const { page, limit } = paginationDto;
const startIndex = (page - 1) * limit;
const endIndex = page * limit;
const paginatedUsers = this.users.slice(startIndex, endIndex);
return {
data: paginatedUsers,
total: this.users.length,
page,
limit,
};
}
}
import { Controller, Get, Query } from '@nestjs/common';
import { UserService } from './user.service';
import { PaginationDto } from './user.dto';
@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) {}
@Get()
findAll(@Query() paginationDto: PaginationDto) {
return this.userService.findAll(paginationDto);
}
}
Pagination의 종류에는 여러 가지가 있습니다
사용자가 특정 페이지 번호를 요청하여 데이터를 가져오는 방식입니다.
예를 들어, GET /users?page=2&limit=10.
각 페이지에 대한 데이터의 "커서"를 사용하여 다음 데이터를 가져오는 방식입니다.
이는 데이터의 위치를 기반으로 하여, 특정 데이터부터 다음 데이터를 가져오는 것입니다.
예: GET /users?after=cursorValue&limit=10.
데이터의 오프셋(시작 위치)을 지정하여 가져오는 방식입니다.
예: GET /users?offset=20&limit=10.
특정 데이터의 키를 사용하여 다음 데이터를 가져오는 방식으로,
성능과 일관성을 유지하는 데 유리합니다.
사용자가 페이지를 이동하는 동안 데이터가 추가되거나 삭제되면, 결과 세트가 바뀌어 이전에 보던 데이터와 다른 데이터가 나타날 수 있습니다.
성능 문제: 대규모 데이터셋에서는 페이지가 깊어질수록 성능 저하가 발생할 수 있습니다.
데이터베이스에서 페이지 번호에 따라 많은 데이터를 건너뛰어야 하므로 비효율적일 수 있습니다.
장점: Cursor-Based Pagination은 이전 페이지의 마지막 항목을 기준으로 다음 페이지를 로드하기 때문에, 데이터 변경 시에도 안정적인 결과를 제공합니다.
사용자가 위치한 항목을 기준으로 다음 데이터를 쉽게 가져올 수 있습니다.
단점: 커서를 사용해야 하므로, 구현이 다소 복잡할 수 있습니다.
또한 커서가 무효화될 경우(예: 데이터가 삭제되거나 변경됨) 문제가 발생할 수 있습니다.
EnableImplicitTransformation은 Nest.js에서 데이터 전송 객체(DTO)와 요청 본문 간의 변환을 자동으로 처리할 수 있도록 설정하는 옵션입니다.
이 설정을 활성화하면, 요청에서 들어온 데이터가 DTO의 타입과 일치하는지 자동으로 검사하고,
필요에 따라 변환을 수행합니다.
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe({ transform: true, whitelist: true }));
await app.listen(3000);
}
bootstrap();
이렇게 설정하면 DTO에서 정의한 데이터 유형에 맞게 들어온 요청을 변환하여 유효성을 검증할 수 있습니다.