Sequelize Models Association: JOIN

조성철 (JoSworkS)·2020년 1월 19일
1

기존 코드와 달라진 점

  1. 데이터베이스 models의 allowNull: false로 번경
    • 기존 외래키와 관련된 column은 allowNull의 validation 문제로 true로 설정해두었지만 false로 재변경하였다.
  const trails = sequelize.define(
    'trails',
    {
      userId: {
        type: DataTypes.INTEGER,
        allowNull: false,
      },
      locationId: {
        type: DataTypes.INTEGER,
        allowNull: false,
      },
      categoryId: {
        type: DataTypes.INTEGER,
        allowNull: false,
      },
      imageId: {
        type: DataTypes.INTEGER,
        allowNull: false,
      },
      title: {
        type: DataTypes.STRING,
        allowNull: false,
      },
      review: {
        type: DataTypes.STRING,
        allowNull: false,
      },
      adminDistrict: {
        type: DataTypes.STRING,
        allowNull: false,
      },
    },
  );
  1. Associate 정의에서 foreignKey의 지정
    • foreignKey에 옵션으로 allowNull을 주었지만 이렇게 할 경우 default로 foreign key가 모델명+Id로 설정되기 때문에 모델들을 아래와 같이 작성해주었다.
  trails.associate = function (models) {
    models.trails.hasMany(models.comments);

    trails.belongsTo(models.locations, {
      foreignKey: 'locationId',
    });
    trails.belongsTo(models.users, {
      foreignKey: 'userId',
    });
    trails.belongsTo(models.categories, {
      foreignKey: 'categoryId',
    });
    trails.belongsTo(models.images, {
      foreignKey: 'imageId',
    });
  };
변경 전 모델사용 예시

Sequelize로 LEFT OUTER JOIN 하기

Sequelize에서 JOIN하는 방법에 대해 먼저 조사해 보았다.(DB: MySQL)

결과부터 말하자면 아래의 옵션을 JOIN할 때 include 내 required로 설정 할 수 있다.

  • 'required: false': LEFT OUTER JOIN
  • 'required: true': INNER JOIN

LEFT OUTER JOIN

LEFT OUTER JOIN은 아래 소스코드와 같이 include의 옵션으로 'required: false' 를 주면 된다.

주요 옵션
  • where: SQL의 where과 같다. 특정한 상태를 만족하는 기록들만 추출하는데 사용된다.
  • include: Sequelize에서 JOIN을 담당한다.
    1. model: JOIN하고자하는 모델(테이블)
    1. required: 'false'는 LEFT OUTER JOIN, 'true'는 INNER JOIN
    2. attributes: SQL의 select와 같다. 디폴트는 '*'으로 모든 column을 필터링
     const checkTrailsByTag = await trails.findAll({
        where: {
          categoryId: checkTag.id,
        },
        include: [
          {
            model: users,
            required: false,
            attributes: ['username'],
          },
          {
            model: locations,
            required: false,
            attributes: ['location1', 'location2', 'location3', 'location4', 'location5'],
          },
        ],
        raw: true,
      })

SQL

SELECT `trails`.`id`, `trails`.`userId`, `trails`.`locationId`, `trails`.`categoryId`, `trails`.`imageId`, `trails`.`title`, `trails`.`review`, `trails`.`adminDistrict`, `trails`.`createdAt`, `trails`.`updatedAt`, `user`.`username` AS `user.username`, `location`.`location1` AS `location.location1`, `location`.`location2` AS `location.location2`, `location`.`location3` AS `location.location3`, `location`.`location4` AS `location.location4`, `location`.`location5` AS `location.location5` FROM `trails` AS `trails` LEFT OUTER JOIN `users` AS `user` ON `trails`.`userId` = `user`.`id` LEFT OUTER JOIN `locations` AS `location` ON `trails`.`locationId` = `location`.`id` WHERE `trails`.`categoryId` = 1;
결과
[
    {
        "id": 1,
        "userId": 1,
        "locationId": 1,
        "categoryId": 1,
        "imageId": 1,
        "title": "test",
        "review": "test",
        "adminDistrict": "yokohama",
        "createdAt": "2020-01-19T04:05:52.000Z",
        "updatedAt": "2020-01-19T04:05:52.000Z",
        "user.username": "1",
        "location.location1": "[1,1]",
        "location.location2": "[2,2]",
        "location.location3": "[3,3]",
        "location.location4": "[4,4]",
        "location.location5": "[5,5]"
    }
]

0개의 댓글