tmkimm
Eddy
tmkimm
전체 방문자
오늘
어제
  • 분류 전체보기 (34)
    • DataBase (3)
    • Javascript (0)
    • Node.js (7)
    • Java (2)
    • Spring (3)
    • 기타 (13)
    • 사이드프로젝트 (2)
    • 생각 정리 (2)
    • 좋은글 공유 (1)

블로그 메뉴

    공지사항

    인기 글

    태그

    • 논쟁
    • 사이드프로젝트
    • Sentry
    • 에러트래킹
    • Git
    • Node.js
    • spring
    • SSL
    • github
    • 부하테스트
    • 삽질기록
    • 생각정리
    • 모니터링
    • 설계
    • docker
    • mybatis
    • Java
    • API 문서 자동화
    • swagger

    최근 댓글

    최근 글

    티스토리

    hELLO · Designed By 정상우.
    tmkimm
    DataBase

    MongoDB에서 효율적으로 페이징 처리하기(pagination)

    DataBase

    MongoDB에서 효율적으로 페이징 처리하기(pagination)

    2022. 11. 11. 17:00

    MongoDB Pagination

    MongoDB에서 페이징을 처리하는 방법은 여러 가지가 있습니다.

    효율적으로 처리하기 위해 했던 고민들을 공유합니다.

     

    개발 환경

    • Node.js(Express)
    • mongoDB(Mongoose)

     

    ❌ Skip, Limit

    처음 적용했던 방식은 mongoDB의 skip과 limit 기능을 이용해서 데이터를 건너뛰고(skip), 한 페이지에 보여줘야 하는 수만큼 제한(skip)하는 것입니다.

    현재 3 페이지고 한 페이지에 10개의 데이터를 보여준다면 21~30 번째 글을 보여주면 되므로 skip(20).limit(10) 가 됩니다.

    db.students.find().skip(20) // 10개를 건너뛰고 21개부터 조회
    db.students.find().limit(10) // 10개만 조회
    db.students.find().skip(20).limit(10) // 20개를 건너뛰고 10개만 조회

     

     

    Node.js에서 페이징을 적용하려면 아래와 같이 작성하면 됩니다.

    const itemsPerPage = 10;
    const page = 3;
    
    const resuilt = await this.students.find({})
        .skip((page - 1) * itemsPerPage)
        .limit(itemsPerPage)

     

    같은 방법으로 페이징이 아닌 무한 스크롤(Infinite Scroll)에도 적용할 수 있습니다.

    시작할 순서(offset)와 조회 개수(limit)를 요청받아 skip과 limit에 그대로 사용하면 됩니다.

    한 번에 20개의 데이터를 조회한다면

    • 최초 조회: offset 0, limit 20
    • 첫 번째 스크롤: offset 20, limit 20
    • 두 번째 스크롤: offset 40. limit 20
    const resuilt = await this.students.find({})
        .skip(offset)
        .limit(limit)

     

    Skip과 Limit의 단점

    1. 성능 저하

    사용하기는 정말 편하지만 find에 해당되는 데이터를 전부 조회한 후 skip과 limit을 적용하기 때문에 성능에 문제가 생길 수 있습니다. 필요한 데이터는 10건인데 매번 전체 데이터를 읽는 것은 비효율적입니다.

     

    2. 데이터 불일치 가능성

    사용자가 3번째 페이지를 읽다가 새로운 글이 등록됐을 경우 4번 페이지로 이동했을 때 같은 글이 중복되어 노출될 수 있습니다. skip & limit은 이 문제를 해결할 수 있는 방법이 없습니다.

     

    skip과 limit 대신 다른 방법이 필요해 보입니다

     


    ✅ Object ID 비교(참고글)

    MongoDB에서 document별로 부여되는 Object ID의 앞자리는 timestamp를 가지고 있습니다. 

    이미지 출처 : https://koonsland.tistory.com/89

    Object ID를 비교하면 어떤 글이 먼저 등록되었는지 알 수 있습니다.(timestamp가 클수록 최신 글입니다)

    // NodeJS로 확인
    if(첫번째로 등록된 글("632862fb37ad6700140c2f11") < 두번째로 등록된 글("63482c55d4143d48ee4d5796")) // true
    
    // MongoDB에서 확인
    {_id: {$gt: ObjectId('632862fb37ad6700140c2f11') }}

    대부분 페이징 처리를 하는 경우 등록일을 오름차순이나 내림차순으로 정렬되어 있습니다.

    즉 데이터가 정렬되어 있는 상태라면 ObjectID를 통해 페이징을 처리할 수 있습니다.

     

    현재 페이지의 마지막 글보다 ObjectID가 큰 데이터를 조회하면 다음 페이지를 가져올 수 있습니다. 

    const result = await this.students.find({ $gt: "1페이지의 마지막 Object ID" })
        .limit(limit)

    이 방법을 사용하면 데이터 전체를 조회하지 않아도 되기 때문에 속도도 개선되고 데이터 중복도 피할 수 있습니다! 👍👍

     

    주의 사항

    이때 find 조건에 $or이 있을 경우 데이터가 섞일 수 있습니다. $and 연산자를 이용하여 데이터가 섞이지 않도록 주의해야 합니다.

     


    여러 페이지 이동

    한 페이지를 이동이 아닌 여러 페이지를 이동할 때는 어떻게 처리해야 할까요?

    현재 페이지는 3 페이지고 이전 페이지가 1일 경우 Object ID 비교와 skip을 같이 사용하면 됩니다.

    const itemsPerPage = 10; // 한 페이지에 표현할 글 수
    let currentPage = 3;	 // 현재 페이지
    let previousPage = 1;    // 이전 페이지
    let pagesToSkip = currentPage - previousPage;    // 이동한 페이지
    
    db.students
    .find({’_id’: {’$gt’: last_id}})
    .skip(itemsPerPage * pagesToSkip)
    .limit(itemsPerPage)

     

    저는 페이지가 앞에서 뒤로 이동할 수도 있으므로 pagesToSkip에 따라 $gt, $lt로 조회하도록 처리했습니다.

    더 좋은 방법이 있다면 댓글로 알려주시면 감사하겠습니다. 🙏

     

     

     

     

    참고 글

    MongoDB Pagination, Fast & Consistent

    Implementing pagination in mongodb

     

    저작자표시 (새창열림)

    'DataBase' 카테고리의 다른 글

    [MongoDB]mongoose에서 가상 필드 조회안하기, Document를 Object로 변환하기  (0) 2021.11.16
    SQL, NoSQL 비교(특징, 스키마, 속도, 확장)  (2) 2021.09.01
    • MongoDB Pagination
    • ❌ Skip, Limit
    • Skip과 Limit의 단점
    • ✅ Object ID 비교(참고글)
    • 여러 페이지 이동
    'DataBase' 카테고리의 다른 글
    • [MongoDB]mongoose에서 가상 필드 조회안하기, Document를 Object로 변환하기
    • SQL, NoSQL 비교(특징, 스키마, 속도, 확장)
    tmkimm
    tmkimm
    ⭐️

    티스토리툴바

    단축키

    내 블로그

    내 블로그 - 관리자 홈 전환
    Q
    Q
    새 글 쓰기
    W
    W

    블로그 게시글

    글 수정 (권한 있는 경우)
    E
    E
    댓글 영역으로 이동
    C
    C

    모든 영역

    이 페이지의 URL 복사
    S
    S
    맨 위로 이동
    T
    T
    티스토리 홈 이동
    H
    H
    단축키 안내
    Shift + /
    ⇧ + /

    * 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.