M x N Association Table에는 기본적으로 참조한 모델의 기본키만 컬럼으로 들어가는데, 추가적으로 컬럼을 넣고 싶다면 모델을 만들어서 만든 모델을 through
로 추가하면 된다.
If you want additional attributes in your join table, you can define a model for the join table in sequelize, before you define the association, and then tell sequelize that it should use that model for joining, instead of creating a new one:
// 참고소스
User = sequelize.define('user', {})
Project = sequelize.define('project', {})
UserProjects = sequelize.define('userProjects', {
status: DataTypes.STRING
})
User.belongsToMany(Project, { through: UserProjects })
Project.belongsToMany(User, { through: UserProjects })
위에 소소는 참고링크에 나와 있는 예이고 아래 예는 내가 실제로 사용한 소스이다.
// 실제 사용 예
// Posthashtag 모델을 참고할 예정
const DataTypes = require('sequelize')
const { Model } = DataTypes
module.exports = class Posthashtag extends Model {
static init(sequelize) {
return super.init(
{
isUse: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true
},
isTemp: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false
},
isTempDeleted: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false
}
},
{
modelName: 'Posthashtag',
tableName: 'posthashtags',
charset: 'utf8mb4',
collate: 'utf8mb4_general_ci',
sequelize
}
)
}
}
// Post 모델
const DataTypes = require('sequelize')
const { Model } = DataTypes
module.exports = class Post extends Model {
static init(sequelize) {
return super.init(
{
...
},
{
modelName: 'Post',
tableName: 'posts',
charset: 'utf8mb4',
collate: 'utf8mb4_general_ci',
sequelize
}
)
}
static associate(db) {
...
db.Post.belongsToMany(db.Hashtag, {
through: db.Posthashtag,
onUpdate: 'CASCADE',
onDelete: 'CASCADE',
foreignKey: 'postId',
sourceKey: 'id'
})
}
}
// Hash tag 모델
const DataTypes = require('sequelize')
const { Model } = DataTypes
module.exports = class Hashtag extends Model {
static init(sequelize) {
return super.init(
{
tag: {
type: DataTypes.STRING(20),
allowNull: false
}
},
{
modelName: 'Hashtag',
tableName: 'hashtags',
charset: 'utf8mb4',
collate: 'utf8mb4_general_ci',
sequelize
}
)
}
static associate(db) {
db.Hashtag.belongsToMany(db.Post, {
through: db.Posthashtag,
onUpdate: 'CASCADE',
onDelete: 'CASCADE',
foreignKey: 'hashtagId',
sourceKey: 'id'
})
}
}
// index.js
const env = process.env.NODE_ENV || 'development'
const Sequelize = require('sequelize')
const post = require('./post')
const hashtag = require('./hashtag')
const posthashtag = require('./posthashtag')
const config = require('../config/config')[env]
const db = {}
const sequelize = new Sequelize(
config.database,
config.username,
config.password,
config
)
db.Posthashtag = posthashtag
db.Hashtag = hashtag
db.Post = post
Object.keys(db).forEach((modelName) => {
db[modelName].init(sequelize)
})
Object.keys(db).forEach((modelName) => {
if (db[modelName].associate) {
db[modelName].associate(db)
}
})
db.sequelize = sequelize
db.Sequelize = Sequelize
module.exports = db
M x N 관계에서는 sequelize에서 제공한 add
,set
,remove
,has
,count
,get
, create
함수를 사용할 수 있다. 관련 정보는 BelongsToMany링크를 참조하면 됨.
이번에 간단히 작성할 예제는 위에서 언급한데로 참조한 기본키값이 아닌 다른 값을 수정할 경우에 사용하는 방법이다.
throught 테이블이 만약 기본키들만 가지고 있는게 아니라 추가로 다른 컬럼을 가지고 있는 모델일 경우 아래와 같이 수정하거나 생성하거나 할 수 있다.
// tag: Hashtag 모델의 instance임.
// Post, Posthashtag (through 테이블 모델: Post x Hashtag)
const isExist = await tag.hasPost(post)
let addedTag = null
if (!isExist) {
addedTag = await tag.addPost(post, {
through: { isTemp: false, isUse: true }
})
} else {
addedTag = await Posthashtag.update(
{ isTemp: false, isTempDeleted: false, isUse: true },
{
where: { postId: post.id, hashtagId: tag.id }
}
)
}
여기서 has
함수를 통해서 이미 연결된 데이터인지 확인하는 이유는 이미 연결된 정보의 경우는 추가 연결이 되지 않음. 즉 수정 안되기 때문. 따라서 연결이 안된 경우는 add
를 통해서 연결을 해주고 이미 연결된 경우에는 해당 모델을 직접 참조해서 update
함수를 사용한다.
Belongs-To-Many associations : v3 버전 문서지만 동일하게 적용되는 부분임을 확인