엘리스 AI트랙 4기/프로젝트

[TypeScript Express] Sequelize 외래키로 참조 테이블 데이터 검색하기

남쪽마을밤송이 2022. 6. 16. 21:56

관련글 1 : https://s0n9h2.tistory.com/109

 

[TypeScript Express] Sequelize로 MySQL 모델 Association 관계 설정하기

관련글 1 : [Typescript Express] Sequelize로 MySQL 연결하기 [Typescript Express] Sequelize로 MySQL 연결하기  [01 Typescript란? ] TypeScript는 JavaScript 기반의 언어이다. JavaScript는 클라이언트..

s0n9h2.tistory.com


 [01 들어가기에 앞서 ] 

  • 저번 포스팅에서 1:1, 1:N, 1:M 관계 설정에 대해 다뤘는데, 이렇게 설정해 둔 외래키로 어떻게 참조 테이블을 검색할 수 있을지 작성해보겠다.
  • 처음 나와 팀원은 당연히(?) 그냥 findAll 혹은 findOne의 where문에 외래키를 넣어주면 된다고 생각했는데, 모델을 생성할 때 Attributes에 외래키가 들어가지 않고 관계 설정시에 컬럼이 추가되기 때문에 외래키를 바로 참조할 수 없었다.
  • 따라서 검색을 해보니 핵심은 외래키가 있는 참조 테이블을  include 하는 것이었는데, 아래에서 자세하게 설명해보겠다.

 

 [02 모델 구조 ] 

  • 먼저 이해를 돕기 위해  Checklists 의 ERD 설계와 모델의 Attributes는 다음과 같다.

  • 위와 같이 외래키  fk_user_id 는 모델 생성시에 Attributes에 있는 것이 아니라 관계 설정시에 외래키 컬럼으로 추가된다.

 

 [03 옵션 설정 ] 

  • sequelize 쿼리 함수를 사용하는 DB 계층 파일  Checklist.ts 에 작성했다.

 (1) where, include 

  • 먼저  findByDate  메소드는 사용자가 오늘 체크리스트를 작성했는지 확인하기 위한 기능이다. 따라서 fk_user_id와 date를 기준으로 데이터가 존재하는지 검색해야 한다.
  • 이 때  fk_user_id 는 외래키이므로  include 옵션을 사용해  model 은 Users (fk_user_id가 참조하는 테이블),  where 에 { Users 테이블에서의 fk_user_id 컬럼명: fk_user_id } 를 설정해주면 된다.
    • include는 말 그대로 다른 모델을 "포함"해서 검색하고 응답한다고 이해했다. 따라서 그 모델에서 필터링할 것(where)과 보여줄 속성(attributes)을 include 옵션 안에서 지정해줄 수 있다.
  • 그리고  date 는 Checklists 모델의 컬럼이기 때문에  include 와 함께 바깥  where 에 설정해줘야 한다.
  findByDate: async (fk_user_id: string, date: Date) => {
    const checklist = await Checklists.findOne({
      where: { date },
      include: { model: Users, where: { pk_user_id: fk_user_id } },
    });
    return checklist;
  }

 (2) attributes, order 

  • 여기서 추가로 Op(연산자)와 더 많은 옵션을 사용해서 구체적인 필터링이 가능하다.
  •  findByWeek  메소드는 사용자가 일주일동안 체크한 체크리스트의 level을 보여주는 기능이다. 따라서 fk_user_id와 일주일의 시작 날짜(start), 끝나는 날짜(finish)를 기준으로 검색해야 한다.
  • 외래키 검색은 위의 예시와 비슷하게 하되, Users 모델의 정보는 필요 없기에  attributes  옵션을  [ ] (빈 값)으로 설정했다.
    • attributes도 말 그대로 보여줄 속성을 정해주는 옵션이다. include로 참조 모델을 포함하면 findAll 함수의 경우 응답의 데이터 양이 엄청 많아지기 때문에 모든 컬럼이 필요하지 않다면 attributes로 필요한 컬럼만 지정해주는 것이 좋다.
  • 또 Checklists 모델에서도 1~6번의 항목값은 필요 없기 때문에  attributes  옵션을 이용해 date와 level만 보여주도록 설정했다.
  • 마지막으로 시간순으로 정렬하기 위해  order  옵션을 이용해서 date 컬럼을  ASC (오름차순)으로 설정했다.
    • 이러한 정렬은 date 컬럼이 dateonly 혹은 datetime 타입일 때 가능하다. 이외에 시간순으로 정렬이 필요하다면 created_at이나 updated_at 컬럼을 사용해야 할 것이다.
    • 내림차순은  DESC 이다.
    • 여러 컬럼을 기준으로 정렬하고 싶다면  [ ] 안에 정렬할 순서대로 ["컬럼명", "정렬기준"]을 추가한다.
  findByWeek: async (fk_user_id: string, { start, finish }: IChecklistWeeklyInput) => {
    const checklists = await Checklists.findAll({
      attributes: ["date", "level"],
      where: { date: { [Op.between]: [start, finish] } },
      include: { model: Users, attributes: [], where: { pk_user_id: fk_user_id } },
      order: [["date", "ASC"]],
    });
    return checklists;
  }
  • Op 연산자 종류와 사용하는 방법은 다음 포스팅으로 다뤄보겠다.