Sequelize 支持标准关联关系: 一对一, 一对多 和 多对多。
为此,Sequelize 提供了 四种 关联类型,并将它们组合起来以创建关联:
- HasOne 关联类型
- BelongsTo 关联类型
- HasMany 关联类型
- BelongsToMany 关联类型
本章将讲解如何定义这四种类型的关联,然后讲解如何将它们组合来定义三种标准关联类型(一对一, 一对多 和 多对多)。
本教程实例代码:https://gitee.com/liqiang88/sequelize-test
本章节需要用到的实例代码中的MySQL 数据,需要执行:
$ node associate/create.js
来创建相应表和数据。
生成的表关系如图:
一对一关系
用户表与用户信息表
一个用户只有一张用户信息表
UserModel:
const { DataTypes } = require('sequelize');
const SequelizeConn = require('../SequelizeConn');
// 用户表
const UserModel = SequelizeConn.define('user', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
username: {
type: DataTypes.STRING,
allowNull: false
},
status: {
type: DataTypes.INTEGER,
allowNull: false,
},
password: {
type: DataTypes.INTEGER,
allowNull: false
},
createdAt: {
type: DataTypes.DATE,
allowNull: true
},
updatedAt: {
type: DataTypes.DATE,
allowNull: true
}
}, {
tableName: 'user'
})
module.exports = UserModel;
UserInfoModel:
const { DataTypes } = require('sequelize');
const SequelizeConn = require('../SequelizeConn');
// 用户信息表
const UserInfoModel = SequelizeConn.define('userInfo', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
user_id: {
type: DataTypes.INTEGER,
allowNull: false
},
birthday: {
type: DataTypes.STRING,
allowNull: true
},
nickname: {
type: DataTypes.STRING,
allowNull: true
},
createdAt: {
type: DataTypes.DATE,
allowNull: true
},
updatedAt: {
type: DataTypes.DATE,
allowNull: true
}
}, {
tableName: 'user_info'
});
module.exports = UserInfoModel;
定义一对一关系:
// 定义关系
// 1----1 一对一关系
User.hasOne(UserInfo, { foreignKey: 'user_id', sourceKey: 'id' });
// UserInfo.belongsTo(User, {foreignKey: 'user_id', targetKey: 'id'})
// User.hasOne(UserInfo, {foreignKey: 'user_id', sourceKey: 'id', as: 'user_info'})
// UserInfo.belongsTo(User, {foreignKey: 'user_id', targetKey: 'id', as: 'user_info'})
一对一查询:
(async () => {
//查询数据
let username = 'runoops';
const userResult = await User.findOne({
where: {
username: username
},
include: [UserInfo]
// include: [
// {model: UserInfo, as: 'user_info'},
// ]
// include: [{all: true}] //所有关联的信息
});
const userRs = userResult.toJSON();
console.log(userRs);
})();
查询结果:
{
id: 1,
username: 'runoops',
status: 1,
password: 123,
createdAt: 2023-05-10T03:48:15.000Z,
updatedAt: 2023-05-10T03:48:15.000Z,
user_info: {
id: 1,
user_id: 1,
birthday: '2011-02-03',
nickname: 'luo',
createdAt: 2023-05-10T03:50:59.000Z,
updatedAt: 2023-05-10T03:50:59.000Z
}
}
注意:
如果在定义关系时,使用as,则在使用include的时候,也需要使用as,且变量需要相同
如果在定义关系是,没有使用as,则在使用include的时候,不能使用as,可以将模型直接写在数组中或者只使用model,不使用as。
不过怎么定义关系,都可以通过include: [{all: true}]的方式来拿到所有关联的信息
一对多关系
给上面的关系增加一个手机表,一个用户可以拥有多个手机
PhoneModel:
const { DataTypes } = require('sequelize');
const SequelizeConn = require('../SequelizeConn');
// 手机表
const PhoneModel = SequelizeConn.define('phone', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
user_id: {
type: DataTypes.INTEGER,
allowNull: false
},
number: {
type: DataTypes.INTEGER,
allowNull: false
},
createdAt: {
type: DataTypes.DATE,
allowNull: true
},
updatedAt: {
type: DataTypes.DATE,
allowNull: true
}
}, {
tableName: 'phone'
});
module.exports = PhoneModel;
定义一对多关系:
// 定义关系
// 1----n 一对多关系
User.hasMany(Phone, { foreignKey: 'user_id', sourceKey: 'id' });
Phone.belongsTo(User, { foreignKey: 'user_id', targetKey: 'id' });
// User.hasMany(Phone, {foreignKey: 'user_id', sourceKey: 'id', as: 'phone'})
// Phone.belongsTo(User, {foreignKey: 'user_id', targetKey: 'id', as: 'phone'})
一对多查询:
(async () => {
//查询数据
let username = 'runoops';
const userResult2 = await User.findOne({
where: {
username: username
},
include: [UserInfo, Phone]
// include: [
// {model: UserInfo, as: 'user_info'},
// {model: Phone, as: 'phone'},
// ]
// include: [{all: true}]
});
const userRs2 = userResult2.toJSON();
console.log(userRs2);
})();
查询结果:
{
id: 1,
username: 'runoops',
status: 1,
password: 123,
createdAt: 2023-05-10T03:48:15.000Z,
updatedAt: 2023-05-10T03:48:15.000Z,
user_info: {
id: 1,
user_id: 1,
birthday: '2011-02-03',
nickname: 'luo',
createdAt: 2023-05-10T03:50:59.000Z,
updatedAt: 2023-05-10T03:50:59.000Z
},
phones: [
{
id: 1,
user_id: 1,
number: 1878788787,
createdAt: 2023-05-10T08:36:38.000Z,
updatedAt: 2023-05-10T08:36:38.000Z
},
{
id: 2,
user_id: 1,
number: 1878788788,
createdAt: 2023-05-10T08:36:38.000Z,
updatedAt: 2023-05-10T08:36:38.000Z
}
]
}
多对多关系
新增课程表course,一门课程有多个学生,一个学生有多门课程
新增中间表user_course,用来关联学生与课程
CourseModel:
const { DataTypes } = require('sequelize');
const SequelizeConn = require('../SequelizeConn');
//课程表
const CourseModel = SequelizeConn.define('course', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
name: {
type: DataTypes.STRING,
allowNull: false
},
createdAt: {
type: DataTypes.DATE,
allowNull: true
},
updatedAt: {
type: DataTypes.DATE,
allowNull: true
}
}, {
tableName: 'course'
});
module.exports = CourseModel;
UserCourseModel:
const { DataTypes } = require('sequelize');
const SequelizeConn = require('../SequelizeConn');
//课程-学生关系表
const UserCourseModel = SequelizeConn.define('userCourse', {
id: {
type: DataTypes.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
user_id: {
type: DataTypes.INTEGER,
allowNull: false
},
course_id: {
type: DataTypes.INTEGER,
allowNull: false
},
createdAt: {
type: DataTypes.DATE,
allowNull: true
},
updatedAt: {
type: DataTypes.DATE,
allowNull: true
}
}, {
tableName: 'user_course'
});
module.exports = UserCourseModel;
定义多对多关系:
// 定义关系
// n----n 多对多关系
Course.belongsToMany(User, { through: UserCourse, foreignKey: 'course_id' });
User.belongsToMany(Course, { through: UserCourse, foreignKey: 'user_id' });
// Course.belongsToMany(User, { through: UserCourse, foreignKey: 'course_id',targetKey: 'id', as: 'user' });
// User.belongsToMany(Course, { through: UserCourse, foreignKey: 'user_id', targetKey: 'id', as: 'course' });
多对多查询:
(async () => {
let username = 'runoops';
//查询用户的选课信息
const userResult3 = await User.findOne({
where: {
username: username
},
include: [UserInfo, Phone, Course]
// include: [
// {model: UserInfo, as: 'user_info'},
// {model: Phone, as: 'phone'},
// {model: Course, as: 'course'},
// ]
// include: [{ all: true }]
});
const userRs3 = userResult3.toJSON();
console.log(userRs3);
})();
查询结果:
{
id: 1,
username: 'runoops',
status: 1,
password: 123,
createdAt: 2023-05-10T03:48:15.000Z,
updatedAt: 2023-05-10T03:48:15.000Z,
user_info: {
id: 1,
user_id: 1,
birthday: '2011-02-03',
nickname: 'luo',
createdAt: 2023-05-10T03:50:59.000Z,
updatedAt: 2023-05-10T03:50:59.000Z
},
phones: [
{
id: 1,
user_id: 1,
number: 1878788787,
createdAt: 2023-05-10T08:36:38.000Z,
updatedAt: 2023-05-10T08:36:38.000Z
},
{
id: 2,
user_id: 1,
number: 1878788788,
createdAt: 2023-05-10T08:36:38.000Z,
updatedAt: 2023-05-10T08:36:38.000Z
}
],
courses: [
{
id: 1,
name: '语文',
createdAt: 2023-05-10T08:36:38.000Z,
updatedAt: 2023-05-10T08:36:38.000Z,
user_course: [Object]
},
{
id: 2,
name: '数学',
createdAt: 2023-05-10T08:36:38.000Z,
updatedAt: 2023-05-10T08:36:38.000Z,
user_course: [Object]
}
]
}
预先加载
通过使用 include 参数 在 Sequelize 中执行预先加载。
上面查询的方式都是用预先加载的方式,详见上面例子,例如:
await User.findOne({ include: UserInfo });
延迟加载
延迟加载是指仅在确实需要时才获取关联数据的技术。
//延迟加载的方式
(async () => {
//1. 先查询 user
let username = 'runoops';
const userResult4 = await User.findOne({
where: {
username: username
}
});
// console.log(userResult4);
// console.log(userResult4.username); //ok
// 2. 再关联查询
const userInfo = await userResult4.getUserInfo();
console.log(userInfo.toJSON());
const userPhone = await userResult4.getPhones();
console.log(userPhone.map(item => item.toJSON()));
})();
结果如下:
$ node associate/querydelay.js
Executing (default): SELECT `id`, `username`, `status`, `password`, `createdAt`, `updatedAt` FROM `user` AS `us
er` WHERE `user`.`username` = 'runoops' LIMIT 1;
Executing (default): SELECT `id`, `user_id`, `birthday`, `nickname`, `createdAt`, `updatedAt` FROM `user_info`
AS `userInfo` WHERE `userInfo`.`user_id` = 1 LIMIT 1;
{
id: 1,
user_id: 1,
birthday: '2011-02-03',
nickname: 'luo',
createdAt: 2023-05-10T03:50:59.000Z,
updatedAt: 2023-05-10T03:50:59.000Z
}
Executing (default): SELECT `id`, `user_id`, `number`, `createdAt`, `updatedAt` FROM `phone` AS `phone` WHERE `
phone`.`user_id` = 1;
[
{
id: 1,
user_id: 1,
number: 1878788787,
createdAt: 2023-05-10T08:36:38.000Z,
updatedAt: 2023-05-10T08:36:38.000Z
},
{
id: 2,
user_id: 1,
number: 1878788788,
createdAt: 2023-05-10T08:36:38.000Z,
updatedAt: 2023-05-10T08:36:38.000Z
}
]
分享笔记