본문 바로가기
Coding/Etc

Sequelize.js Association belongsToMany 정리

by Hide­ 2018. 7. 16.
반응형

Belongs-To-Many associations

BelongsToMany는 source를 여러개의 target에 연결할 때 사용한다.

게다가 target또한 여러개의 source에 연결될 수 있다.

Project.belongsToMany(User, {through: 'UserProject'});
User.belongsToMany(Project, {through: 'UserProject'});

위 코드는 projectIduserId라는 외래키를 포함하고 있는 UserProject라는 새로운 모델을 생성할 것이다. 

속성이 카멜케이스가 될지, 아닐지는 두개의 모델이 조인했을때에 따라 다르다. (이 경우에는 User와 Project)

추가적으로, through 를 무조건 정의해줘야 한다.

(예전에는 Sequelize에서 자동으로 이름을 생성했는데 이는 비직관적이고 논리적인 이름이 아니기 때문이다.)


위 작업을 진행하고나면 User 모델에 getProjects, setProjects, addProject, and addProjects 라는 메소드가 생기고

Project 모델에는 getUsers, setUsers, addUser,addUsers 라는 메소드가 생긴다.


가끔씩 관계를 사용할 때 사용하는 모델의 이름을 바꾸고 싶을 때가 있다.

이럴 때는 아래처럼 as 옵션을 사용하여 users를 workers로, projects를 tasks로 바꿔줄 수 있다.

또한 foreignKey 옵션도 같이 줘서 수동으로 외래키를 지정해줄 것이다.

User.belongsToMany(Project, { as: 'Tasks', through: 'worker_tasks', foreignKey: 'userId' })
Project.belongsToMany(User, { as: 'Workers', through: 'worker_tasks', foreignKey: 'projectId' })


foreignKey 옵션을 통해 through 모델에 source 모델의 키를 생성할 수 있다.

또한  otherKey 옵션을 통해 through 모델에 target 모델의 키를 생성할 수 있다.

User.belongsToMany(Project, { as: 'Tasks', through: 'worker_tasks', foreignKey: 'userId', otherKey: 'projectId'})


추가적으로 자기 자신을 참조하는 belongsToMany도 가능하다:

Person.belongsToMany(Person, { as: 'Children', through: 'PersonChildren' })
// 위 라인은  PersonChildren이라는 테이블을 생성한다. This will create the table PersonChildren which stores the ids of the objects.


만약 join한 테이블에 추가적인 속성을 부여하고 싶다면 관계를 굳이 새로 생성할 필요는 없다. 관계를 define하기 전에

sequelize의 기본 기능을 통해 정의해줄 수 있기 때문이다.

그리고 이것이 join 테이블을 위한 것이라고 sequelize에게 알려주기만 하면 된다.

const User = sequelize.define('user', {})
const Project = sequelize.define('project', {})
const UserProjects = sequelize.define('userProjects', {
    status: DataTypes.STRING
})

User.belongsToMany(Project, { through: UserProjects })
Project.belongsToMany(User, { through: UserProjects })

User모델에 새로운 project를 추가하고 그것의 상태를 추가해주고 싶다면

join 테이블에 포함되어있는 setter에 options.through 옵션을 주면 된다. 

user.addProject(project, { through: { status: 'started' }})


기본적으로 아래의 코드는 projectId와 userId를 UserProjects에 추가할 것이다.

그리고 이전에 정의된 PK를 제거한다.

해당 테이블은 두 테이블에 의해 조합된 키를 PK로 사용할 것이며 다른 PK값은 가지지 않는다.

UserProjects 테이블에 PK를 추가하기 위해서는 수동으로 정의해줘야 한다.

const UserProjects = sequelize.define('userProjects', {
  id: {
    type: Sequelize.INTEGER,
    primaryKey: true,
    autoIncrement: true
  },
  status: DataTypes.STRING
})


BelongsToMany 관계를 지정한 모델에서 특정 컬럼을 조회하고 싶다면 through를 사용하면 된다.

아래의 코드는 through를 통해 findAll을 실행시킨 예제이다.

User.findAll({
  include: [{
    model: Project,
    through: {
      attributes: ['createdAt', 'startedAt', 'finishedAt'],
      where: {completed: true}
    }
  }]
});