https://softmoca.tistory.com/315
페이지 네이션 전반적인 내용은 위 게시물을 참조 !
1) 커서 기반 페이지 네이션
게시물 20개의 오름차순 정렬된 게시물 가져오기
오름 차순 페이지네이션을 위한 기본 dto생성
export class PaginatePostDto {
// 이전 마지막 데이터의 ID
// 이 프로퍼티에 입력된 ID 보다 높은 ID 부터 값을 가져오기
@IsNumber()
@IsOptional()
where__id__more_than?: number;
// 정렬
// createdAt -> 생성된 시간의 오름차 순으로 정렬
@IsIn(["ASC"])
@IsOptional()
order__createdAt: "ASC" = "ASC";
// 몇개의 데이터를 응답으로 받을지
@IsNumber()
@IsOptional()
take: number = 20;
}
post.controller와 post.service
@Get()
// @UseInterceptors(LogInterceptor)
getPosts(@Query() query: PaginatePostDto) {
return this.postsService.paginatePosts(query);
}
// 1) 오름차 순으로 정렬하는 pagination만 구현한다
async paginatePosts(dto: PaginatePostDto) {
const posts = await this.postsRepository.find({
where: {
id: MoreThan(dto.where__id__more_than ?? 0),
},
order: {
createdAt: dto.order__createdAt,
},
take: dto.take,
});
return { data: posts };
}
main.ts
app.useGlobalPipes(
new ValidationPipe({
transform: true,
})
);
dto의 정렬의 기본 디폴트 값으로 ASC 즉, 오름차순으로 된 값을 dto단에서 처리하기 위해 transform 옵션을 true로 한다.
그럼 현재 22개의 게시물 중 오름차순으로 20개의 게시물만 가져올 수 있다 !
다음 20개의 게시물 데이터 가져 오기
id가 1-20까지의 데이터를 조회 했으니 이제 21-40까지의 다음 페이지 게시물 데이터를 조회 해야한다.
id가 20 이상인 게시물을 쿼리로 요청을 하면 아래와 같이 에러가 나온다.
그 이유로 쿼리는 url에 있는 것이기 때문에 숫자 형태로 입력하더라고 string으로 간주가 된다.
그래서 string을 숫자 형태로 변환을 해줘야 한다. 그걸 바로 classtransformer가 해준다.
paginat-post.dto.ts
@Type(()=>Number)
@IsNumber()
@IsOptional()
where__id__more_than?: number;
위와 같이 타입 변환을 Type어노테이션을 사용하면 string이 number타입으로 변환되어 에러 없이 쿼리 실행 잘 된다.
main.ts
app.useGlobalPipes(
new ValidationPipe({
transform: true,
transformOptions: {
enableImplicitConversion: true,
},
})
);
하지만 매 속성마다 Type 어노테이션을 붙이지 않고 위와 같이 enableImplicitConversion을 true로 해주면
@IsNumber()
@IsOptional()
where__id__more_than?: number;
위와 같이 IsNumber 어노테이션을 확인하고 '아 ! 숫자가 와야 하는구나 !' 라고 인식해 자동으로 string을 Number타입으로 변환시켜준다. 즉, 어노테이션에 작성된 타입을 기반으로 자동으로 class-transformer가 작동하여 타입을 변환 한다.
다음 페이지를 가져오기 위한 cursor와 nextURL [+내림차순]
export class PaginatePostDto {
// 이전 마지막 데이터의 ID
// 이 프로퍼티에 입력된 ID 보다 높은 ID 부터 값을 가져오기
@IsNumber()
@IsOptional()
where__id__more_than?: number;
@IsNumber()
@IsOptional()
where__id__less_than?: number;
내림 차순을 위한 where__id__less_than 옵션 추가.
async paginatePosts(dto: PaginatePostDto) {
const where: FindOptionsWhere<PostModel> = {};
if (dto.where__id__less_than) {
where.id = LessThan(dto.where__id__less_than);
} else if (dto.where__id__more_than) {
where.id = MoreThan(dto.where__id__more_than);
}
const posts = await this.postsRepository.find({
where,
order: {
createdAt: dto.order__createdAt,
},
take: dto.take,
});
쿼리가 less이냐 more이냐에 따라 다른 필터링 where 객체 생성하여 분기처리한다.
post.service.ts
const lastItem = posts.length > 0 && posts.length === dto.take ? posts[posts.length - 1] : null;
해당되는 포스트가 0개 이상이면서 take와 길이가 같다(다음페이지 데이터가 더 있다)면 마지막 포스트를 가져오고 아니면 null을 반환한다. null은 다음 페이지의 데이터가 이제 없다는 뜻이다.(즉, 마지막 페이지)
const nextUrl = lastItem && new URL(`${protocol}://${host}/posts`);
if (nextUrl) {
for (const key of Object.keys(dto)) {
if (dto[key]) {
if (
key !== "where__id__more_than" &&
key !== "where__id__less_than"
) {
nextUrl.searchParams.append(key, dto[key]);
}
}
}
let key = null;
if (dto.order__createdAt === "ASC") {
key = "where__id__more_than";
} else {
key = "where__id__less_than";
}
nextUrl.searchParams.append(key, lastItem.id.toString());
}
return {
data: posts,
cursor: {
after: lastItem?.id ?? null,
},
count: posts.length,
next: nextUrl?.toString() ?? null,
};
}
dto의 키값들을 루핑하면서 키값에 해당되는 벨류가 존재하면 param에 그대로 붙여넣는다.
단, where__id_more_than과 less_than 값만 lastItem의 마지막 값으로 넣어준다.
그럼 이제 내림차순 또한 다음 페이지를 조회 하기 위한 nextURL와 cursor가 잘 나온다.
2) 페이지 기반 페이지 네이션
export class PaginatePostDto {
@IsNumber()
@IsOptional()
page?: number;
페이지 네이션 dto에 page 속성 추가.
async pagePaginatePosts(dto: PaginatePostDto) {
const [posts, count] = await this.postsRepository.findAndCount({
skip: dto.take * (dto.page - 1),
take: dto.take,
order: {
createdAt: dto.order__createdAt,
}
});
return {
data: posts,
total: count,
}
}
페이지의 갯수를 구하기 위해 total과 dto.take을 알려준다.
위와 같이 페이지 별로 게시물 데이터를 정렬 하려 잘 가져올 수 있다.
'캡스톤 설계 [건물별 소통 플랫폼 BBC]' 카테고리의 다른 글
인터셉터과 트랜잭션을 활용한 게시물 작성 [파일 업로드] (0) | 2024.03.25 |
---|---|
페이지네이션 일반화 하기 (2) | 2024.03.24 |
유효성 체크 [DTO && Class Validator/Transformer] + 게시물 수정+비밀번호 안보이게하기 (0) | 2024.03.08 |
포스트맨 기능활용[환경변수,토큰 삽입 자동화] (0) | 2024.03.07 |
[백엔드] 회원가입,로그인(JWT토큰&리프레시 토큰&가드&커스텀데코레이터) [2] (0) | 2024.03.07 |