일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 한국건설관리시스템
- 생성자오버로드
- 오라클
- 다형성
- abstract
- cursor문
- 컬렉션 타입
- 객체 비교
- 참조형변수
- exception
- 사용자예외클래스생성
- Java
- 환경설정
- oracle
- 집합_SET
- 자동차수리시스템
- 제네릭
- 인터페이스
- GRANT VIEW
- 정수형타입
- 메소드오버로딩
- 컬렉션프레임워크
- EnhancedFor
- 대덕인재개발원
- 자바
- 어윈 사용법
- 추상메서드
- 예외처리
- 예외미루기
- NestedFor
- Today
- Total
거니의 velog
(20) mongoose를 이용한 MongoDB 연동 실습 9 본문
(4) 페이지 기능 구현
* 페이지 기능을 구현할 준비가 어느 정도 끝났다. 페이지 기능을 구현하려면 앞 절에서 배운 limit 함수를 사용해야 하고, 추가로 skip 함수도 사용해야 한다.
* skip이란 표현에는 '넘긴다'라는 의미가 있다. skip 함수에 파라미터로 10을 넣어 주면, 처음 열 개를 제외하고 그 다음 데이터를 불러온다. 20을 넣어 준다면? 처음 20개를 제외하고 그다음 데이터 열 개를 불러온다.
* 대충 감이 잡혔을 것이다. skip 함수의 파라미터에는 (page - 1) * 10을 넣어 주면 된다.1페이지는 처음 열 개를 불러오고, 2페이지에는 그다음 열 개를 불러오게 된다. page 값은 query에서 받아 오도록 설정한다.
이 값이 없으면 page 값을 1로 간주하여 첫 페이지로 초기화하도록 코드를 작성해 보겠다.
[src/api/posts/posts.ctrl.js]
/*
GET /api/posts
*/
export const list = async (ctx) => {
// query 는 문자열이기 때문에 숫자로 변환해주어야합니다.
// 값이 주어지지 않았다면 1 을 기본으로 사용합니다.
const page = parseInt(ctx.query.page || '1', 10);
if (page < 1) {
ctx.status = 400;
return;
}
try {
const posts = await Post.find()
.sort({ _id: -1 }) // 내림차순 정렬
.limit(10) // 한 번에 보여줄 게시물을 10개로 제한
.skip((page - 1) * 10) // 페이징 처리(1페이지당 10개씩 보여주기)
.exec();
ctx.body = posts;
} catch (e) {
ctx.throw(500, e);
}
};
이렇게 하면 http://localhost:4000/api/posts?page=2 와 같은 형식으로 페이지를 지정하여 조회할 수 있다.
(5) 마지막 페이지 번호 알려 주기
* 지금도 페이지로서 기능은 충분하다. 하지만 조금만 더 기능을 추가해 보자. 마지막 페이지를 알 수 있다면 클라이언트가 더욱 편할 것이다. 응답 내용의 형식을 바꾸어 새로운 필드를 설정하는 방법, Response 헤더 중 Link를 설정하는 방법, 커스텀 헤더를 설정하는 방법으로 이 정보를 알려 줄 수도 있다.
* 이 중에서 우리는 커스텀 헤더를 설정하는 방법을 사용해 볼 것이다.
[src/api/posts/posts.ctrl.js]
/*
GET /api/posts
*/
export const list = async (ctx) => {
// query 는 문자열이기 때문에 숫자로 변환해주어야합니다.
// 값이 주어지지 않았다면 1 을 기본으로 사용합니다.
const page = parseInt(ctx.query.page || '1', 10);
if (page < 1) {
ctx.status = 400;
return;
}
try {
const posts = await Post.find()
.sort({ _id: -1 }) // 내림차순 정렬
.limit(10) // 한 번에 보여줄 게시물을 10개로 제한
.skip((page - 1) * 10) // 페이징 처리(1페이지당 10개씩 보여주기)
.exec();
const postCount = await Post.countDocuments().exec(); // 포스팅된 글 갯수 카운트
ctx.set('Last-Page', Math.ceil(postCount / 10)); // [전체 포스팅된 글 갯수 / 10] 하면 '총 페이지 수' 나옴. 올림(ceil)하는 이유는 나머지 값이 1~9 사이가 나와도 무조건 1페이지가 추가되어야 하기 때문
ctx.body = posts;
} catch (e) {
ctx.throw(500, e);
}
};
* Last-Page 라는 커스텀 HTTP 헤더를 설정했다. 이 값이 제대로 나타나는지 Postman을 이용하여 확인해 보자.
* Last-Page 값이 잘 나타난다.
(6) 내용 길이 제한
* 이제 body의 길이가 200자 이상이면 뒤에 '...'을 붙이고 문자열을 자르는 기능을 구현해 볼 것이다. find()를 통해 조회한 데이터는 mongoose 문서 인스턴스의 형태이므로 데이터를 바로 변형할 수 없다. 그 대신 toJSON() 함수를 실행하여 JSON 형태로 변환한 뒤 필요한 변형을 일으켜 주어야 한다.
* list 함수를 다음과 같이 수정해 보자.
[src/api/posts/posts.ctrl.js]
/*
GET /api/posts
*/
export const list = async (ctx) => {
// query 는 문자열이기 때문에 숫자로 변환해주어야합니다.
// 값이 주어지지 않았다면 1 을 기본으로 사용합니다.
const page = parseInt(ctx.query.page || '1', 10);
if (page < 1) {
ctx.status = 400;
return;
}
try {
const posts = await Post.find()
.sort({ _id: -1 }) // 내림차순 정렬
.limit(10) // 한 번에 보여줄 게시물을 10개로 제한
.skip((page - 1) * 10) // 페이징 처리(1페이지당 10개씩 보여주기)
.exec();
const postCount = await Post.countDocuments().exec(); // 포스팅된 글 갯수 카운트
ctx.set('Last-Page', Math.ceil(postCount / 10)); // [전체 포스팅된 글 갯수 / 10] 하면 '총 페이지 수' 나옴. 올림(ceil)하는 이유는 나머지 값이 1~9 사이가 나와도 무조건 1페이지가 추가되어야 하기 때문
ctx.body = posts
.map((post) => post.toJSON()) // 1. 먼저 JSON 객체로 변환한다.
.map((post) => ({
...post,
body:
post.body.length < 200 ? post.body : `${post.body.slice(0, 200)}...`, // 2. 글자수가 200 미만이면 그대로 출력하고 200을 넘으면 생략처리
}));
} catch (e) {
ctx.throw(500, e);
}
};
* 또 다른 방법으로 데이터를 조회할 때 lean() 함수를 사용하는 방법이 있다. 이 함수를 사용하면 데이터를 처음부터 JSON 형태로 조회할 수 있다.
/*
GET /api/posts
*/
export const list = async (ctx) => {
// query 는 문자열이기 때문에 숫자로 변환해주어야합니다.
// 값이 주어지지 않았다면 1 을 기본으로 사용합니다.
const page = parseInt(ctx.query.page || '1', 10);
if (page < 1) {
ctx.status = 400;
return;
}
try {
const posts = await Post.find()
.sort({ _id: -1 }) // 내림차순 정렬
.limit(10) // 한 번에 보여줄 게시물을 10개로 제한
.skip((page - 1) * 10) // 페이징 처리(1페이지당 10개씩 보여주기)
.lean() // 처음부터 데이터를 JSON으로 조회하도록 처리
.exec();
const postCount = await Post.countDocuments().exec(); // 포스팅된 글 갯수 카운트
ctx.set('Last-Page', Math.ceil(postCount / 10)); // [전체 포스팅된 글 갯수 / 10] 하면 '총 페이지 수' 나옴. 올림(ceil)하는 이유는 나머지 값이 1~9 사이가 나와도 무조건 1페이지가 추가되어야 하기 때문
ctx.body = posts.map((post) => ({
...post,
body:
post.body.length < 200 ? post.body : `${post.body.slice(0, 200)}...`,
}));
} catch (e) {
ctx.throw(500, e);
}
};
* 코드를 저장한 뒤 Postman으로 list API를 호출해 보자. body 길이가 200자로 잘 제한되었는가?
11. 정리
* 이 장에서는 REST API 에서 MongoDB를 연동하는 방법을 배우고, 쿼리를 작성하여 페이지네이션 기능까지 구현해 보았다. MongoDB는 여기서 다룬 것 이외에 더욱 다양하고 복잡한 쿼리도 설정할 수 있다.
* 백엔드는 결국 여러 가지 조건에 따라 클라이언트에서 전달받은 데이터를 등록하고 조회하고 수정하는 것이다. 우리가 만든 백엔드 서버에는 현재 한 종류의 데이터 모델과 REST API밖에 없지만, 프로젝트 규모에 따라 더욱 많은 종류의 모델과 API를 관리할 수도 있다.
* 다음에는 User라는 데이터 모델을 만들어서 회원 인증 시스템을 구현해 보겠다.
'React_백엔드 프로그래밍' 카테고리의 다른 글
(22) JWT를 통한 회원 인증 시스템 구현하기 2 (0) | 2024.02.21 |
---|---|
(21) JWT를 통한 회원 인증 시스템 구현하기 1 (0) | 2024.02.21 |
(19) mongoose를 이용한 MongoDB 연동 실습 8 (0) | 2024.02.21 |
(18) mongoose를 이용한 MongoDB 연동 실습 7 (0) | 2024.02.21 |
(17) mongoose를 이용한 MongoDB 연동 실습 6 (0) | 2024.02.20 |