본문 바로가기
Study Note/React

React #mongoose #페이지네이션 구현

by 시뮝 2021. 3. 17.
728x90

React와 mongoose로 페이지네이션 구현

mongoose란?

  • mongoose란, mongoDB라는 NoSQL 데이터베이스를 지원하는 노드의 확장모듈이다.
  • mongoose는 mongoDB의 ODM(Object Document Mapping)이다. 문서를 DB에서 조회할 때 자바스크립트 객체로 바꿔주는 역할을 한다.

페이지네이션이란?

화면에 출력할 데이터 양이 많은 경우 한 화면에 전부 보여줄 수 없어 끊어 보여주는 것을 말한다.

 

페이지네이션 함수

  • find() : 조회
  • sort() : 순서대로 조회
  • limit() : 조회 개수
  • skip() : 넘길 개수
  • lean() : plain JSON 객체를 받아온다.

 

 

직접 쿼리를 작성해서 페이지 기능 구현

Post 목록을 조회하는 listAPI이다. Post.find()로 목록을 조회하는 쿼리문을 exec()로 실행한다.

// src/models/post.js
const mongoose = require('mongoose');

const { Schema } = mongoose;
Post = new Schema({
  (...)
});

module.exports = mongoose.model('Post', Post);
// src/api/posts/posts.ctrl.js
const Post = require('../../models/post');

/* GET /api/posts
 */
exports.list = async (ctx) => {
    try {
        const posts = await Post.find().exec();
        ctx.body = posts;
    } catch(e) {
        ctx.throw(e, 500);
    }
};

 

포스트 역순으로 불러오기

find()와 exec() 사이에 sort()를 구문을 넣으면 순서대로 목록을 조회할 수 있다. sort 함수의 파라미터는 { key: 1 }형식으로 넣으며 key는 소팅할 필드를 설정하는 부분이다. _id를 내림차순으로 정렬하는 { _id: -1}로 설정한다.

  • 오른쪽 값을 1로 설정하면 오름차순으로 정렬한다.
  • 오른쪽 값을 -1로 설정하면 내림차순으로 정렬한다.
exports.list = async (ctx) => {
    try {
        const posts = await Post.find().sort({_id: -1}).exec();
        ctx.body = posts;
    } catch(e) {
        ctx.throw(e, 500);
    }
};

 

보이는 개수 제한하기

개수를 제한할 때는 limit 함수를 사용한다. 5개로 제한한다면 limit(5)로 입력한다.

exports.list = async (ctx) => {
    try {
        const posts = await Post.find()
            .sort({_id: -1})
            .limit(5)
            .exec();
        ctx.body = posts;
    } catch(e) {
        ctx.throw(e, 500);
    }
};

 

페이지 기능 구현

페이지 기능을 구현하려면 limit과 skip 함수를 사용해야 한다. skip 함수에 5를 넣으면 첫 5개를 제외하고, 그 다음 데이터를 불러온다. (page-1)*5 를 넣으면 1페이지에는 처음 5 개를 불러오고, 2페이지에는 그 다음 5개를 불러온다.

exports.list = async (ctx) => {
    // page가 주어지지 않았다면 1로 간주
    // query는 문자열 형태로 받아 오므로 숫자로 변환
    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(5)
            .skip((page - 1) * 10)
            .exec();
        ctx.body = posts;
    } catch(e) {
        ctx.throw(e, 500);
    }
};

1페이지 5개를 불러온다.

 

마지막 페이지 번호 알려 주기

마지막 페이지 번호를 알려 주는 방법은 다양하다. 이 중에서 커스텀 헤더를 설정하는 방법을 사용한다.

  • 응답 내용의 형식을 바꾸어 새로운 필드를 설정하는 방법
  • Response 헤더 중 Link를 설정하는 방법
  • 커스텀 헤더를 설정하는 방법
exports.list = async (ctx) => {
    // page가 주어지지 않았다면 1로 간주
    // query는 문자열 형태로 받아 오므로 숫자로 변환
    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(5)
            .skip((page - 1) * 10)
            .exec();
        const postCount = await Post.countDocuments().exec();
        // 마지막 페이지 알려 주기
        // ctx.set은 response header를 설정
        ctx.set('Last-Page', Math.ceil(postCount / 10));
        ctx.body = posts;
    } catch(e) {
        ctx.throw(e, 500);
    }
};

 

Last-Page라는 커스텀 HTTP 헤더를 설정했다. 제대로 나타나는지 Postman으로 확인해보면 아래와 같이 5라고 나온다. 

 

 

마지막 페이지 번호가 진짜 10이 맞는지 Robo 3T에서 데이터 수를 조회해보니 46개가 나왔다. 맞게 나온 것으로 확인되었다.

 

내용 길이 제한

길이가 100자 이상이면 뒤에 ...을 붙이고 문자열을 자르는 기능을 lean()으로 구현한다. 

 

exports.list = async (ctx) => {
    // page가 주어지지 않았다면 1로 간주
    // query는 문자열 형태로 받아 오므로 숫자로 변환
    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(5)
            .skip((page - 1) * 5)
            .lean()
            .exec();
        const postCount = await Post.countDocuments().exec();
        const limitBodyLength = post => ({
            ...post,
            body: post.body.length < 100 ? post.body : `${post.body.slice(0,100)}...`
        });
        ctx.body = posts.map(limitBodyLength);
        // 마지막 페이지 알려 주기
        // ctx.set은 response header를 설정
        ctx.set('Last-Page', Math.ceil(postCount / 5));
    } catch(e) {
        ctx.throw(e, 500);
    }
};

 

Postman으로 확인

 


 

 


 

728x90

댓글