본문 바로가기
All Side/Runtime > NodeJS

백엔드에서 페이지네이션 하는 방법 2가지 MongoDB or JavaScript

by developerBeluga 2023. 2. 10.
728x90
반응형

 

 

페이지네이션

페이지네이션은 데이터를 컨트롤 방식이 아닌 버튼 형식으로 보여주는 방식을 말한다.

방대한 데이터를 다룬다면 끝없이 내려가는 컨트롤 방식보다는 버튼 형식이 더 낫다고 생각한다.

 

백엔드 개발자이기 때문에 프론트가 아닌 백엔드에서 데이터 전달 시에 어떻게 페이지네이션 할 수 있는지 알아보도록 하자.

 

 

1. MongoDB 메소드 사용하기

가장 간단하면서, 자주 사용하는 방식이 아닐까 생각한다.

 

const page = Number(req.query.page || 1); // 현재페이지
const perPage = Number(req.query.perPage || 10); // 페이지 당 게시글 수
const total = await Post.countDocument({});

// MongoDB 함수 사용하기
const posts = await Post.find({}) 
    .skip(perPage * (page - 1))
    .limit(perPage);
    
const totalPage = Math.ceil(total / perPage);

skip()과 limit를 사용하면 간단하게 한 페이지당 n개의 데이터만 전달되게 할 수 있다.

limit는 검색 결과 수를 제한하기 위해 사용되고, skip은 검색 시 포함하지 않을 데이터의 수이다.

 

 

 

하지만..!

예를 들어, A라는 작품에 B라는 댓글을 달았다고 해보자.

B 댓글을 조회하면 A 작품 Id를 가지고 있다.

댓글이라는 데이터를 화면에 그려주기 위해서는 A라는 작품의 정보 또한 필요하다.

 

우리는 당연히 A 작품 Id를 가지고 있으니 A 데이터를 조회하면 된다.

그럼 여기에서 문제가 나타난다.

MongoDB를 이용한 페이지네이션을 어디에 시켜줄 것인가?

 

find로 찾은 B 댓글 데이터에? 아님 findOne으로 찾은 A 작품 데이터에?

result = [
	// 첫번째 댓글과 worId로 조회한 해당 작품 정보
  {
    business: {
      _id: new ObjectId("63e082f02e6334d683d7bc1d"),
      workId: '630c4778e1c2997ed87b7d91',
      ...
    },
    workData: {
      _id: new ObjectId("630c4778e1c2997ed87b7d91"),
      ...
    }
  },
  	// 두번째 댓글과 worId로 조회한 해당 작품 정보
  {
    business: {
      _id: new ObjectId("63b67446caa6730bdda92daa"),
      workId: '63b3dcf183da64ad7d95c867',
      ...
    },
    workData: {
      _id: new ObjectId("63b3dcf183da64ad7d95c867"),
      ...
    }
  },
  	// 세번째 댓글과 worId로 조회한 해당 작품 정보
  {
    business: {
      _id: new ObjectId("63b6327d4d5309899fc47209"),
      workId: '63b3dcf183da64ad7d95c867',
      ...
    },
    workData: {
      _id: new ObjectId("63b3dcf183da64ad7d95c867"),
      ...
    }
  }
  ...
]

심지어 클라이언트에 보내주기 위해 하나의 배열에 두개의 데이터를 담고 있는 하나의 객체가 여러개 들어가게 된다.

즉, 새로운 배열에서 페이지네이션을 해줘야 한다는 것이다.

(MongoDB 메소드 사용 못함)

 

 

2. slice() 이용하기

하지만 생각보다 해결 방법은 쉽다.

바로 JavaScript에서 제공해주는 slice()라는 함수를 써주면 된다.

slice()는 어떤 배열 begin부터 end까지에 대한 얉은 복사본을 새로운 배열 객체로 반환하는 배열이다.

한마디로 n번째 인덱스부터 n번째 인덱스까지 잘라 새로운 배열로 만들어주는 함수다!

 

// 페이지네이션
const page = Number(req.query.page || 1);
const perPage = Number(req.query.perPage || 10);

const pagination = result.slice(perPage * (page - 1), perPage * page);

페이지네이션을 하기 위해서는 3가지 정보가 필요하다.

1. page : 현재 페이지

2. perPage : 페이지 당 게시글 수

3. result : (두개의 데이터를 합친) 데이터 

 

page가 1로 들어오면 pagination 구분은 0-9가 되어야 한다.

page가 2로 들어오면 pagination 구분은 10-19가 되어야 한다.

page가 3이면? 20-29가 되어야 한다.

그러기 위해서 perPage * (page - 1), perPage * page라는 수식을 이용해주면 된다!

 

솔직히 이 방법은 백엔드에서 굳이 할 필요는 없다.

배열을 프론트에 보내주면 프론트에서 slice를 사용하든 다른 라이브러리를 사용하든 구현하면 된다.

그렇기 때문에 실무일 경우 합의하에 하면 될 것 같다.

 

 

추가로

총 페이지의 수를 원하는 경우가 있을 수 있다.

const total = result.length;
const totalPage = Math.ceil(total / perPage);

그럴 경우 result 배열의 길이를 계산해 Math.ceil에 페이지 당 게시글 수를 계산해주면 된다.

 

 

 

 

마무리

페이지네이션을 구현한 적이 한 번 밖에 없었고 그때는 MongoDB 메소드로 해결 가능했다.

 

하지만 하나의 데이터가 아니라 두개의 데이터를 페이지네이션 할려고 하니 처음엔 위 짤처럼 ㅋㅋㅋ 어리둥절이었다.

그렇기 때문에 포스팅하기로 했다.

왜냐하면 나중에 또 어리둥절 할 수 있으니..!

 

 

 

 

 

728x90
반응형

댓글