백엔드 개발자(node.js)가 되는 과정

Sequelize로 MySQL JOIN하기

soopy 2023. 6. 21. 19:13
728x90

MySQL의 JOIN 적용을 위한 준비

게시글 작성 사이트를 예시로 들어보자.
데이터베이스에는 유저 테이블과 게시글 테이블이 구분되어 있을 것이고, 게시글 테이블을 통해 해당 게시글의 작성자가 누구인지, 좀 더 깊게 들어가서 작성자의 이메일은 무엇인지 알기 위해서는 두 테이블 간 JOIN 작업이 필요할 것이다. sequelize를 통해 두 테이블을 JOIN 해서 정보를 획득하는 방법에 대해 알아보자

두 테이블의 관계 설정

// 유저 모델과 포스트 모델 간 1대 다 관계 설정

// models/user.js
static associate(models) {
  this.hasMany(models.Post, {
    sourceKey: 'id',
    foreignKey: 'userId',
  });
}

// models/post.js
static associate(models) {
  this.belongsTo(models.User, {
    targetKey: 'id',
    foreignKey: 'userId',
});
}

우선 sequelize의 migrate를 통해 생성된 models 파일을 살펴본다.
만약 migrate를 통해 User 모델과 Post 모델이 생성되었다고 가정했을 때 각각의 코드에는 associate라는 staticmethod가 있을 것이다. 해당 란에 위와 같이 각 모델 파일을 수정해 준다.

위 예시의 경우 유저와 게시글 테이블 간의 관계를 1대 Many로 설정하고 있다. 유저의 입장에서 게시글은 여러 개 작성할 수 있지만 게시글의 입장에서는 본인의 작성자는 단 한명이기 때문이다.

그래서 models/user.js 모델에 hasMany 메서드를 적용하여 User의 id와 Post의 userId 필드를 엮어준다.
그리고 models/post.js 모델의 경우 1대 다 중 '다'에 해당하므로 해당 케이스는 belongsTo 메서드를 통해 위와 같이 코드를 작성해준다.

저렇게하면 이제 sequelize의 CRUD 메서드 사용 시 include 메서드를 활용하여 JOIN 쿼리를 간접적으로 날릴 수 있게 된다.

예시를 살펴보자

// sequelize
const getPosts = async (req, res) => {
  const getPosts = await Post.findAll({
    attributes: {
      exclude: ['userId'],
    },
    include: [
      {
        model: User,
        attributes: ['id', 'username', 'role'],
      },
    ],
    order: [['createdAt', 'DESC']],
  });
};

포스트 정보를 GET 하는 함수에서 findAll을 통해 Post테이블 데이터를 모두 불러오며, 이 과정에서 userId 필드를 제외한다. 그 이유는 이후 include 메서드를 통해 User 모델을 불러와 해당 모델에 담긴 필드를 불러오면서 유저 id를 가져올 것이기 때문이다. (굳이 userId에 대한 정보가 중복되어 reponse될 필요가 없기 때문이다.) 마지막으로 게시글 조회 시 게시일 기준으로 내림차순 정렬이 되도록 설정하였다.

{
    "posts": [
        {
            "id": 3,
            "title": "cat이 작성한 테스트 타이틀입니다.",
            "content": "3번째 테스트 내용 입니다.",
            "createdAt": "2023-06-21T05:15:47.000Z",
            "updatedAt": "2023-06-21T05:15:47.000Z",
            "User": {
                "id": 3,
                "username": "cat",
                "role": "user"
            },
        },
    ]
}

결과적으로 위 예시처럼 post에 대한 정보 안에 User 정보를 함께 가져올 수 있게 된다.

728x90
728x90