페이지네이션 정렬이 안되는 이슈

wellbeing-dough·2023년 12월 17일
1

1. 문제상황


Slice 무한스크롤로 구현하는 상황에 데이터가 중복되는 상황이 일어났다... 문제의 api는 인기순인 투표를 조회하는 쿼리이다

ERD의 일부이다

vote에 투표를 하면 vote_result가 생기는데 인기순으로 조회하려면 vote에 해당되는 vote_result가 많으면 많을수록 인기순이 높아진다


이 코드 이다 현재 Slice를 구현하기 위해 limit + 1해서 List로 반환하고(hasNext를 알기 위해)

@Component
public class PageableConverter {
    private static final int INDEX_OF_START_SUBLIST = 0;

    public <T> SliceImpl<T> convertListToSlice(List<T> list, int pageNum, int pageSize) {
        if (list.isEmpty()) {
            return new SliceImpl<>(list);
        }

        if (list.size() < pageSize) {
            pageSize = list.size();
        }

        Pageable pageable = PageRequest.of(pageNum, pageSize);

        int start = INDEX_OF_START_SUBLIST;
        int end = Math.min((start + pageable.getPageSize()), list.size());

        List<T> subList = new ArrayList<>(list.subList(start, end));

        boolean hasNext = end < list.size();

        return new SliceImpl<>(subList, pageable, hasNext);
    }

}

이렇게 Slice객체로 바꿔준다

2. 해결과정

page = 0, size = 3넣으면

"voteSlice": {
    "content": [
      {
        "voteId": 19,
        "postedUserId": 1,
        "title": "경북의 자존심, 골라주세요!",
        "detail": "솔직히 경북 술은 고도리 복숭아 와인이 진리인데\n친구녀석이 자꾸 문경바람 백자가 진리라고 하니까 너무 분함 ㅡㅡ\n\n복숭아 맛있는데...문경 술 좋아한다네요\n\n\n아 그래도 복숭아와인이 짱인데!\n술맛도 모르는 녀석이 까부네\n\n님덜 얼른 어떤 술이 진리인지 골라주셈\n골라주면 복받을거임 ❤️ ",
		.....
      },
      {
        "voteId": 34,
        "postedUserId": 16,
        "title": "오늘 행궁동 가는데 어떤거 마실까요?",
        "detail": "행궁동 전통주 바 가는데 요거 두개가 제 맘에 들어요~~~ 하나 결정해주시면 그걸로 오늘 마실게요 ^ㅠ^",
        .....
      },
      {
        "voteId": 28,
        "postedUserId": 3,
        "title": "삼양춘 술 먹어보신분 있나요?",
        "detail": "이번에 인천으로 여행을 가게 되었는데 삼양춘 술들이 유명하더라고요 \n그래서 하나 마셔보려고 합니다.\n생약주랑 탁주 드셔보신분 계신가요? 알려주세요!",
        .....

      }

이렇게 나오고 여기서 page = 1, size = 3넣으면

      {
        "voteId": 28,
        "postedUserId": 3,
        "title": "삼양춘 술 먹어보신분 있나요?",
        "detail": "이번에 인천으로 여행을 가게 되었는데 삼양춘 술들이 유명하더라고요 \n그래서 하나 마셔보려고 합니다.\n생약주랑 탁주 드셔보신분 계신가요? 알려주세요!",

        .....

이렇게 나온다 28번이 한번 더 나온다

여기서 그냥 page = 0 size = 4넣으면

"voteSlice": {
    "content": [
      {
        "voteId": 19,
        "postedUserId": 1,
        "title": "경북의 자존심, 골라주세요!",
        "detail": "솔직히 경북 술은 고도리 복숭아 와인이 진리인데\n친구녀석이 자꾸 문경바람 백자가 진리라고 하니까 너무 분함 ㅡㅡ\n\n복숭아 맛있는데...문경 술 좋아한다네요\n\n\n아 그래도 복숭아와인이 짱인데!\n술맛도 모르는 녀석이 까부네\n\n님덜 얼른 어떤 술이 진리인지 골라주셈\n골라주면 복받을거임 ❤️ ",
		.....
      },
      {
        "voteId": 34,
        "postedUserId": 16,
        "title": "오늘 행궁동 가는데 어떤거 마실까요?",
        "detail": "행궁동 전통주 바 가는데 요거 두개가 제 맘에 들어요~~~ 하나 결정해주시면 그걸로 오늘 마실게요 ^ㅠ^",
        .....
      },
      {
        "voteId": 32,
        "postedUserId": 41,
        "title": "부산 여행을 갑니다!!",
    	"detail": "친구들과 여행가게되서 소주,맥주 보단 부산 막걸리를 한번 먹어보려는데 막걸리 어떤게 부산항을 진하게 느낄 수 있을까요?.
        .....
      },
      {
        "voteId": 28,
        "postedUserId": 3,
        "title": "삼양춘 술 먹어보신분 있나요?",
        "detail": "이번에 인천으로 여행을 가게 되었는데 삼양춘 술들이 유명하더라고요 \n그래서 하나 마셔보려고 합니다.\n생약주랑 탁주 드셔보신분 계신가요? 알려주세요!",
        .....

page = 0 size = 3을 했을때 쿼리 내부에서 limit + 1해서 voteId 19 34 32 28 까지 나오는데 여기서
page = 1 size = 3을 하면 limit + 1해서 voteId 32 39 33 28이 나온다 28이 짤려야되는데 32가 짤리고 28이 두번나온다 결론은 28은 중복되고 32가 짤리는 것이였다 이유가 예상이 된다 vote result 의 개수가 32 와 28이 5로 같아서 였다
쿼리를 직접 limit + 1해서 실행해보니 예상이 맞았다


해결방법은 orderBy(vote.id.count desc, created date desc) 이걸로 인기순이 동률이면 최신순으로 조회하면 해결이 된다

0개의 댓글

관련 채용 정보