최종 프로젝트 - supabase filter 메소드를 잘 말아보자...

하영·2024년 10월 30일
1

팀프로젝트

목록 보기
19/27

댓글을 달면 경험치가 쌓이고 이 값을 활용해서 레벨업을 시켜주는 로직을 구현했다.
처음에는 정말 막막했는데 튜터님 + 팀원분들의 힌트 덕분에 생각보다 오래걸리지 않고 해결할 수 있었다.
supabase에서 제공하는 메소드를 대충 알고 썼는데 이번 기회에 세밀하게 알게된 것 같다.

레벨 업 기능 구현하기 + 약간의 트러블슈팅..? 💥

초기 코드 👩🏻‍💻

import { supabase } from "@/supabase/supabase";

// 경험치에 따라 레벨을 반복적으로 업데이트하는 함수
export const updateUserRank = async (userId: string) => {
  try {
    const { data: userData, error: userError } = await supabase
      .from("USER_TABLE")
      .select("user_exp, user_rank")
      .eq("user_id", userId)
      .single();

    if (userError || !userData) {
      console.error("사용자 데이터 불러오기 실패", userError?.message);
      return;
    }

    let { user_exp, user_rank } = userData;

    // 반복적으로 다음 레벨 기준을 가져와 경험치를 업데이트
    while (true) {
      const { data: rankData, error: rankError } = await supabase
        .from("RANK_TABLE")
        .select("rank_base")
        .order("rank_base", { ascending: true })
        .gt("rank_base", user_exp) // 현재 경험치보다 높은 레벨 기준을 가져오기
        .limit(1);

      if (rankError || !rankData || rankData.length === 0) {
        console.log("레벨 기준 데이터 불러오기 실패", rankError?.message);
        break; // 다음 레벨이 없으면 종료
      }

      const nextRankBase = rankData[0].rank_base;

      // 경험치가 다음 레벨 기준보다 낮으면 반복 종료
      if (user_exp < nextRankBase) {
        break;
      }

      // 다음 레벨 기준을 넘어서면 레벨업
      user_rank += 1;
      user_exp -= nextRankBase;
    }

    // 최종적으로 USER_TABLE에 업데이트된 경험치와 레벨을 반영
    const { error: updateError } = await supabase
      .from("USER_TABLE")
      .update({ user_exp, user_rank })
      .eq("user_id", userId);

    if (updateError) {
      console.log("USER_TABLE 업데이트 오류", updateError.message);
    } else {
      console.log("USER_TABLE 업데이트 성공", { user_exp, user_rank });
    }
  } catch (error) {
    console.error("레벨 업데이트 중 오류 발생:", error);
  }
};

난이도 설정하는 코드를 다른 팀원분이 반복문을 사용해서 구현하셨다고 해서 나도 반복문을 써봤다.

while문을 쓴 이유는 몇 번 반복해야하는지 정해지지 않을 떈 while문을 쓴다고 들어서 작성해보았다.

발생한 문제점 😭

랭킹 계산 로직이 전혀 안 되었다… 푸칵칵
랭킹 숫자가 supabase에 반영이 되지 않고 있었다.

console.log를 찎어서 확인했을 때 “레벨 기준 데이터 불러오기 실패 undefined” 가 나오고 있었고 비교할 대상이 없으니 당연히 반복문도 실행되지 않았던 것..!

RANK_TABLE을 기준으로 경험치 값을 비교하고 있었는데 이 부분의 값 설계를 잘못해두었었다..ㅎ

RANK_TABLErank_base 컬럼이 100,200이 아니라 1,2로 설정되어있어서 발생한 오류였고 이를 고쳐주니 레벨 기준 데이터를 불러오는건 성공했다.



하지만..? 다시 생각해보기 🤔

가만 생각해보니 굳이 반복문을 돌릴게 있나? 싶었다.

단순히 데이터 값만 RANK_TABLE 과 비교하면 끝인 문제인데?

다시 생각한 로직

1. USER_TABLE의 user_exp과  RANK_TABLE의 exp 값을 비교한다.

2. USER_TABLE의 user_exp가 RANK_TABLE의 exp 컬럼의 숫자에 도달하면(일치하면) 

3. RANK_TABLE의 rank_base의 값이 USER_TABLE의 user_rank에 반영된다.

4.  레벨이 변경되고 브라우저에 보여진다.

테이블 구조 재변경.. 하기 🤯

  • rank_base: 레벨 값 (1, 2, 3 등)
  • exp: 각 레벨에 도달하는 데 필요한 user_exp 기준 (100, 200, 300 등)

코드 수정하기

import { supabase } from "@/supabase/supabase";

// 경험치에 따라 레벨을 업데이트하는 함수
export const updateUserRank = async (userId: string) => {
  try {
    const { data: userData, error: userError } = await supabase
      .from("USER_TABLE")
      .select("user_exp, user_rank")
      .eq("user_id", userId)
      .single();

    if (userError || !userData) {
      console.error("사용자 데이터 불러오기 실패", userError?.message);
      return;
    }

    let { user_exp, user_rank } = userData;

    // RANK_TABLE에서 현재 경험치에 맞는 레벨 가져오기
    const { data: rankData, error: rankError } = await supabase
      .from("RANK_TABLE")
      .select("rank_base, exp")
      .eq("exp", user_exp) // ✅ user_exp와 일치하는 레벨 기준 가져오기
      .single();

    if (rankError || !rankData) {
      console.log("레벨 기준 데이터 불러오기 실패", rankError?.message);
      return; // 조건에 맞는 레벨 기준이 없으면 ㅂㅂ
    }

    const { rank_base } = rankData;

    // 현재 레벨과 데이터베이스 레벨 비교 후 업데이트
    if (user_rank !== rank_base) {
      user_rank = rank_base;
      const { error: updateError } = await supabase
        .from("USER_TABLE")
        .update({ user_rank })
        .eq("user_id", userId);

      if (updateError) {
        console.log("USER_TABLE 업데이트 오류", updateError.message);
      } else {
        console.log("USER_TABLE 업데이트 성공", { user_exp, user_rank });
      }
    }
  } catch (error) {
    console.error("레벨 업데이트 중 오류 발생:", error);
  }
};

또 발생한 문제점 💥

일단 되긴 하지만..! 정확히 exp 값과 일치하는! 100,200 값이어야만하고 130 같은 값이 있으면 fetch 에러가 생기고 있었다…🫨

ㅇ ㅏ.. 대충 알잘딱해서 비교해줘야지이이읶!!!!!


최종 수정 코드 ✅

const { data: rankData, error: rankError } = await supabase
      .from("RANK_TABLE")
      .select("rank_base, exp")
      .lte("exp", user_exp) // user_exp 이하의 exp를 가져오기
      .order("exp", { ascending: false }) // exp 기준 내림차순으로 정렬
      .limit(1); // 가장 높은 exp 기준 한 개만 가져오기

RANK_TABLE 쿼리 수정:

  • lte("exp", user_exp): user_exp 이하의 경험치를 가진 레벨을 가져오기
  • order("exp", { ascending: false }): 경험치가 가장 높은 레벨을 먼저 가져오기 위해 내림차순으로 정렬
  • limit(1): 상위 한 개의 레벨 기준만 가져오기

이렇게 하니까 280 값을 줘도 오류도 나지 않고 바로바로 레벨과 경험치가 브라우저, DB에 반영되었다 👍



다음 레벨의 기준을 찾기 위해 사용한 메소드

  • order("rank_base", { ascending: true }):
    • rank_base 컬럼을 오름차순(ascending)으로 정렬하여 가장 낮은 기준부터 높은 기준으로 순서를 정렬

      → 현재 경험치보다 높은 기준 중 가장 낮은 기준을 우선적으로 가져올 수 있게 된다

  • .gt("rank_base", user_exp):
    • 현재 user_exp보다 높은 rank_base 값을 가진 레벨만 가져오도록 설정

      → 현재 경험치를 초과하는 다음 레벨의 기준을 찾아오는 조건

  • .limit(1):
    • 조건을 만족하는 다음 레벨 기준 한 개만 가져오도록 제한

    • rank_base 기준을 오름차순으로 정렬했으므로, 조건에 맞는 가장 낮은 rank_base가 한 개만 선택


결론 : 공식문서를 아주 아주 아주 꼼꼼히 보고 생각을 잘 하자!!!^^👊🏻👊🏻


참고 자료 : https://supabase.com/docs/reference/javascript/lte

profile
왕쪼랩 탈출 목표자의 코딩 공부기록

0개의 댓글

관련 채용 정보