본문 바로가기
프로젝트

24/09/24 - [팀] 풋살 온라인(3): 보유한 선수 목록 & 랭킹 조회

by Jini_Lamp 2024. 9. 24.

본 프로젝트에서는 가챠 시스템을 통해 게임을 진행할 선수를 뽑고, 자신이 가지고 있는 선수를 기반으로 팀을 만들어 게임을 진행한다.

그러기 위해선 먼저 자신이 어떤 선수를 갖고 있는지 알아야 한다. 하여, 해당 값을 UserPlayer 라는 테이블에 집어 넣고, 모든 선수들이 저장되어 있는 Player 테이블과 N:1 관계를 맺고, 마찬가지로 누구의 선수인지 알기 위해 User 테이블과도 N:1 관계를 맺었다.

  • UserPlayer 테이블
더보기
// 유저가 보유한 선수 모델
model UserPlayer {
  id        Int      @id @default(autoincrement())           // 고유 ID
  userId    Int                                              // 유저 ID
  playerId  Int                                              // 선수 템플릿 ID
  teamId    Int?                                             // 소속 팀 ID (null 가능)
  level     Int      @default(0)                             // 선수의 강화 레벨 (기본값 0)
  value     Int      @default(0)                             // 선수의 가치 (기본값 0) < 서버에서 계산 후 저장
  createdAt DateTime @default(now())                         // 생성 시간
  updatedAt DateTime @updatedAt                              // 마지막 업데이트 시간

  // N:1 관계 - 한 명의 유저가 여러 명의 선수를 보유할 수 있음
  user      User     @relation(fields: [userId], references: [id])   // 소유한 유저

  // N:1 관계 - 한 명의 유저 선수는 하나의 선수 템플릿과 연결됨
  player    Player   @relation(fields: [playerId], references: [id]) // 선수 템플릿

  // N:1 관계 - 한 명의 유저 선수는 하나의 팀에 소속될 수 있음 (optional)
  team      Team?    @relation(fields: [teamId], references: [id])   // 소속 팀
}

 

나는 해당 테이블을 바탕으로 유저가 보유한 선수 목록을 각져오는 API를 구현했다.

// 유저의 모든 선수를 가져옴
export const getAllPlayer = async (req, res, next) => {
  try {
    const { userId } = req.user;

    const playerData = await prisma.userPlayer.findMany({
      where: { userId },
      select: {
        id: true,
        level: true,
        teamId: true,
        // N:1 관계를 맺은 Player 테이블을 통해
        // 성수들의 이름, 스탯 정보 가져오기
        player: {
          select: {
            name: true,
            speed: true,
            goalScoring: true,
            shotPower: true,
            defense: true,
            stamina: true,
          },
        },
      },
    });

    res.status(200).json({ playerData });
  } catch (error) {
    next(error);
  }
};

 

 

 

다음은 랭킹 API이다.

랭킹은 크게 두 종류로 확인할 수 있는데, 하나는 승리(wins) 횟수이고, 다른 하나는 구단 가치(totalValue)이다. 어떤 것을 기준으로 볼지는 클라이언트에서 입력을 받는 방식으로 진행되었다.(원래는 DB에 데이터 삽입하는 기능 만들 때 완성했던건데 이제서야 올리는 중....ㅋㅋㅋ)

export const getRanking = async (req, res, next) => {
  try {
    const { sortType } = req.body;
    let sortTypeField;

    switch (sortType) {
      case 'wins':
        sortTypeField = 'wins';
        break;
      case 'totalValue':
        sortTypeField = 'totalValue';
        break;
      default:
        sortTypeField = 'totalValue';
        break;
    }

    const user = await prisma.user.findMany({
      select: {
        username: true,
        totalValue: true,
        wins: true,
        losses: true,
        draws: true,
      },
      orderBy: {
        [sortTypeField]: 'desc', // 구단점수/승리횟수가 높은 순으로 유저를 정렬한다.
      },
    });

    // totalValue가 bigint라 string로 변경(json에서는 bigint를 지원하지 않는다고 한다.)
    const totalValueToString = user.map((user) => ({
      ...user,
      totalValue: user.totalValue.toString(),
    }));

    return res.status(200).json({ data: totalValueToString });
  } catch (error) {
    next(error);
  }
};

 

여기서 알아둬야 할 것은, totalValue은 BigInt로 설정되어 있다.

그러나 JSON에서는 BigInt를 지원하지 않는다. 하여, 해당 부분을 String으로 변환하여 출력하는 방식으로 진행했다.

    // totalValue가 bigint라 string로 변경(json에서는 bigint를 지원하지 않는다고 한다.)
    const totalValueToString = user.map((user) => ({
      ...user,
      totalValue: user.totalValue.toString(),
    }));