[Sequelize] Super Many-to-Many association

가영·2021년 3월 30일
0

우리는 이제 Many-to-Many와 One-to-Many 관계를 쓰임에 따라 비교할 수 있는데, 그 결론으로 "Super Many-to-Many relationship"의 개념에 다다른다.

우리가 만약 시퀄라이즈로 UserProfileGrant라는 through table을 통해 Many-to-Many relationship을 만들려면 다음과 같이 사용하면 된다.

User.belongsToMany(Profile, { through: Grant });
Profile.belongsToMany(User, { through: Grant });

이 코드는 자동으로 Grant라는 테이블에 userIdprofileId라는 컬럼을 추가해준다.


내가 궁금했던 것이다.

Using One-to-Many relationships instead

위의 다대다 관계로 정의하는 대신에 다음처럼 한다면 어떻게 될까?

// Setup a One-to-Many relationship between User and Grant
User.hasMany(Grant);
Grant.belongsTo(User);

// Also setup a One-to-Many relationship between Profile and Grant
Profile.hasMany(Grant);
Grant.belongsTo(Profile);

결과는 같다!
이 코드에서도, User.hasMany(Grant)Profile.hasMany(Grant)Grant에 자동으로 userId, profileId 컬럼을 추가하기 때문이다.

This shows that one Many-to-Many relationship isn't very different from two One-to-Many relationships. The tables in the database look the same.


그럼 차이점은?

유일한 차이점은: 시퀄라이즈로 eager load를 수행할 때

  • with Many-to-Many approach
// you can do:
User.findAll({ include: Profile });
Profile.findAll({ include: User });
// However, you can't do:
User.findAll({ include: Grant });
Profile.findAll({ include: Grant });
Grant.findAll({ include: User });
Grant.findAll({ include: Profile });
  • with the double One-to-Many approach
// you can do:
User.findAll({ include: Grant });
Profile.findAll({ include: Grant });
Grant.findAll({ include: User });
Grant.findAll({ include: Profile });
// However, you can't do:
User.findAll({ include: Profile });
Profile.findAll({ include: User });

// Although you can emulate those with nested includes, as follows:
User.findAll({
  include: {
    model: Grant,
    include: Profile
  }
});

// 근데 이건 너무 불편했었다.

그래서 가장 좋은 방법은,, 바로

the Super Many-to-Many relationship

우리는 단순히 두가지 접근 방법을 다음과 같이 합칠 수 있다.

// The Super Many-to-Many relationship
User.belongsToMany(Profile, { through: Grant });
Profile.belongsToMany(User, { through: Grant });
User.hasMany(Grant);
Grant.belongsTo(User);
Profile.hasMany(Grant);
Grant.belongsTo(Profile);

이 방법으로 우리는 다음의 모든의 eager loading을 가능하기 할 수 있다.

// All these work:
User.findAll({ include: Profile });
Profile.findAll({ include: User });
User.findAll({ include: Grant });
Profile.findAll({ include: Grant });
Grant.findAll({ include: User });
Grant.findAll({ include: Profile });

이런식으로 deeply nested includes도 사용 가능하다 😀

User.findAll({
  include: [
    {
      model: Grant,
      include: [User, Profile]
    },
    {
      model: Profile,
      include: {
        model: User,
        include: {
          model: Grant,
          include: [User, Profile]
        }
      }
    }
  ]
});

출처 : 시퀄라이즈 api reference

0개의 댓글