sequelize에서 foreign key 설정하기

Hazel_Song·2020년 10월 17일
4

SERVER_EXPRESS

목록 보기
6/11

데이터들은 실제로 단발적이고 독립적으로 구성되어 있는 것이 아니라,
서로서로가 연결되어 있다.

따라서 DB구성 시에, 특히 sequelize로 작업할 때, 외래키(foreign key)를 어떻게 설정하는 지에 대해서 정리해 보고자 한다.

foreign key 설정에 대한 설명이 담긴 공식문서
foreign key 설정에 대한 추가 블로그

외래키를 설정하고자 여기저기 구글링을 해보았고, 공식문서 혹은 공식문서에 기반한 위의 게시글들을 발견하게 되었다.

위의 글들은 migration을 통해 table을 만들고, 그에 따라 만들어진
각 모델들에 특정 코드를 추가하라고 안내되어 있었다.

가령, users 테이블의 id 값과 bootcamp_lists 테이블의 id 값을 N:N의 관계로 설정하고자 하면, 각각의 model 파일에

//bootcamp_list의 id는 users 테이블과 다대다 관계이므로 가상의 users_bootcamp라는 테이블을 통해 연결되어있음을 명시
static associate(models) {
      // define association here
      bootcamp_list.belongsToMany(models.users, {through: 'users_bootcamp', targetKey:'id', foreignKey: 'bootcamp_id'})
    }

static associate(models) {
      // define association here
      users.belongsToMany(models.bootcamp_list, {through: 'users_bootcamp', targetKey:'id', foreignKey:'users_id'})
    }

처음에는 연결해주는 역할을 하는 users_bootcamp 테이블까지 별도로 만들어준 다음에, 위에서 설명한 대로 belongsToMany 메소드를 추가해주었다.

결과는 아무런 일도 일어나지 않았다....
(왠지 그럴거 같았다.)

따라서 여기저기 구글링을 꼼꼼하게 해본 결과, stackoverflow에서 답을 찾았다.(역시...)
관련한 스택오버플로우 링크

sequelize로 foreign key 설정해주기

내가 진행했던 과정을 차근차근 정리해보고자 한다.

  • 우선 다대다 관계의 경우 가상의 테이블이 하나더 생기게된다.
    이 테이블은 마이그레이션으로 생성해주면 안된다.

  • users 테이블을 마이그레이션을 통해 만들어주고,
    npx sequelize-cli migration:generate --name users_fk_edit
    해당 터미널 명령어를 통해, users 테이블을 수정하기 위한 마이그레이션 파일을 하나 더 만들어 주었다.

  • 그리고 기존 users의 기본 구성에 then으로 외래키를 추가해주는 함수를 넣어주었다.

module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.createTable('users', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER
      },
      email: {
        type: Sequelize.STRING
      },
      password: {
        type: Sequelize.STRING
      },
      githubId: {
        type: Sequelize.STRING
      },
      active: {
        type: Sequelize.BOOLEAN
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    }).then(function(){
      queryInterface.createTable('users_bootcamp', {
        users_id:{
          type: Sequelize.INTEGER,
          references:{model: 'users', key: 'id'}
        }
      })
    })
  },

즉, users의 id값을 레퍼런스로 가지는 users_bootcamp 테이블을 만들어 주고, 그 테이블의 연결된 외래키로 users_id를 생성!
->mysql로 확인하니까 잘 만들어진 것을 확인했다.

  • 다대다 관계이므로 또 다른 테이블 또한 users와 비슷한 터미널 명령어로 수정버전의 마이그레이션을 만들어 준다.
module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.createTable('bootcamp_lists', {
      id: {
        allowNull: false,
        autoIncrement: true,
        primaryKey: true,
        type: Sequelize.INTEGER
      },
      name: {
        type: Sequelize.STRING
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    }).then(function(){
      queryInterface.addColumn('users_bootcamp','bootcamp_id',{
          type: Sequelize.INTEGER,
          references:{model: 'bootcamp_lists', key: 'id'}
      })
    })
  },

->users와 다른점이 있다면, 이번에는 테이블을 만들어주는 것이 아니라,
만들어진 테이블에 칼럼을 추가 하는 것이므로 addColumn 메소드를 사용해준다.

이렇게 만들고 나서 sequel Pro와 mysql을 통해 확인해보니 다대다 연결 테이블인 user_bootcamp가 잘 만들어져 있었다!

fakedata 넣을 때 seed 작업

외래키가 있을 경우에는 seed 작업 또한 기존과는 다르게 작업해 주어야했다.
foreign key있을 경우, seed 파일 기재에 대한 참고 링크

module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.bulkInsert('users', [
      {
        email: 'thdguswn93@naver.com',
        password: '1234',
        githubId: 'hyunju-song',
        active: true,
        createdAt: new Date(),
        updatedAt: new Date(),
      },
    ]);

    await queryInterface.bulkInsert('bootcamp_lists', [
      {
        name: 'codestates',
        createdAt: new Date(),
        updatedAt: new Date(),
      },
    ]);

    const users = await queryInterface.sequelize.query(`SELECT id FROM users;`);
    const bootcamp = await queryInterface.sequelize.query(`SELECT id FROM bootcamp_lists`);
    const usersRows = users[0];
    const bootcampRows = bootcamp[0];

    await queryInterface.bulkInsert('users_bootcamp', [
      {
        users_id: usersRows[0].id,
        bootcamp_id: bootcampRows[0].id,
      },
    ]);

    return await queryInterface.bulkInsert('reviews', [
      {
        users_id: usersRows[0].id,
        bootcamp_id: bootcampRows[0].id,
        githublink: 'https://github.com/codestates/SAFU-server.git',
        price: '비쌈',
        level: '어려움',
        recommend: '추천',
        curriculum: '어려움',
        comment: '자기주도 학습!!!!중심이다',
        active: true,
        createdAt: new Date(),
        updatedAt: new Date(),
      },
    ]);
  },

  down: async (queryInterface, Sequelize) => {
    await queryInterface.bulkDelete('users', null, {});
    await queryInterface.bulkDelete('bootcamp_lists', null, {});
    await queryInterface.bulkDelete('users_bootcamp', null, {});
    await queryInterface.bulkDelete('reviews', null, {});
  },
};
profile
코드 한 줄로, 세상의 가치를 만들자🌟

0개의 댓글