多对多关联
多对多关联用于将源与多个目标相连接. 此外,目标也可以连接到多个源.
Project.belongsToMany(User, {through: 'UserProject'});
User.belongsToMany(Project, {through: 'UserProject'});
这将创建一个名为 UserProject 的新模型,具有等效的外键projectId
和userId
. 属性是否为camelcase
取决于由表(在这种情况下为User
和Project
)连接的两个模型.
定义 through
为 required. Sequelize 以前会尝试自动生成名称,但并不总是导致最合乎逻辑的设置.
这将添加方法 getUsers
, setUsers
, addUser
,addUsers
到 Project
, 还有 getProjects
, setProjects
, addProject
, 和 addProjects
到 User
.
有时,你可能需要在关联中使用它们时重命名模型. 让我们通过使用别名(as
)选项将 users 定义为 workers 而 projects 定义为t asks. 我们还将手动定义要使用的外键:
User.belongsToMany(Project, { as: 'Tasks', through: 'worker_tasks', foreignKey: 'userId' })
Project.belongsToMany(User, { as: 'Workers', through: 'worker_tasks', foreignKey: 'projectId' })
foreignKey
将允许你在 through 关系中设置 source model 键.
otherKey
将允许你在 through 关系中设置 target model 键.
User.belongsToMany(Project, { as: 'Tasks', through: 'worker_tasks', foreignKey: 'userId', otherKey: 'projectId'})
当然你也可以使用 belongsToMany 定义自我引用:
Person.belongsToMany(Person, { as: 'Children', through: 'PersonChildren' })
// 这将创建存储对象的 ID 的表 PersonChildren.
来源(Source)键 和 目标(Target)键
如果要创建不使用默认主键的 belongsToMany 关系,则需要进行一些设置工作.
你必须为 belongsToMany 的两端设置恰当的 sourceKey
(targetKey
可选).此外,你还必须确保在关系中创建适合的索引.例如:
const User = this.sequelize.define('User', {
id: {
type: DataTypes.UUID,
allowNull: false,
primaryKey: true,
defaultValue: DataTypes.UUIDV4,
field: 'user_id'
},
userSecondId: {
type: DataTypes.UUID,
allowNull: false,
defaultValue: DataTypes.UUIDV4,
field: 'user_second_id'
}
}, {
tableName: 'tbl_user',
indexes: [
{
unique: true,
fields: ['user_second_id']
}
]
});
const Group = this.sequelize.define('Group', {
id: {
type: DataTypes.UUID,
allowNull: false,
primaryKey: true,
defaultValue: DataTypes.UUIDV4,
field: 'group_id'
},
groupSecondId: {
type: DataTypes.UUID,
allowNull: false,
defaultValue: DataTypes.UUIDV4,
field: 'group_second_id'
}
}, {
tableName: 'tbl_group',
indexes: [
{
unique: true,
fields: ['group_second_id']
}
]
});
User.belongsToMany(Group, {
through: 'usergroups',
sourceKey: 'userSecondId'
});
Group.belongsToMany(User, {
through: 'usergroups',
sourceKey: 'groupSecondId'
});
如果你想要连接表中的其他属性,则可以在定义关联之前为连接表定义一个模型,然后再说明它应该使用该模型进行连接,而不是创建一个新的关联:
class User extends Model {}
User.init({}, { sequelize, modelName: 'user' })
class Project extends Model {}
Project.init({}, { sequelize, modelName: 'project' })
class UserProjects extends Model {}
UserProjects.init({
status: DataTypes.STRING
}, { sequelize, modelName: 'userProjects' })
User.belongsToMany(Project, { through: UserProjects })
Project.belongsToMany(User, { through: UserProjects })
要向 user 添加一个新 project 并设置其状态,你可以将额外的 options.through
传递给 setter,其中包含连接表的属性
user.addProject(project, { through: { status: 'started' }})
默认情况下,上面的代码会将 projectId 和 userId 添加到 UserProjects 表中, 删除任何先前定义的主键属性 - 表将由两个表的键的组合唯一标识,并且没有其他主键列. 要在 UserProjects
模型上强添加一个主键,你可以手动添加它.
class UserProjects extends Model {}
UserProjects.init({
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
status: DataTypes.STRING
}, { sequelize, modelName: 'userProjects' })
使用多对多你可以基于 through 关系查询并选择特定属性. 例如通过 through 使用findAll
User.findAll({
include: [{
model: Project,
through: {
attributes: ['createdAt', 'startedAt', 'finishedAt'],
where: {completed: true}
}
}]
});
当通过模型不存在主键时,Belongs-To-Many会创建唯一键. 可以使用 uniqueKey 选项覆盖此唯一键名.
Project.belongsToMany(User, { through: UserProjects, uniqueKey: 'my_custom_unique' })