Sequelize
Datatypes 文档open in new window
概念
模型
模型是 Sequelize 的本质. 模型是代表数据库中表的抽象。
模型也是 ES6 类. 类的实例表示该模型中的一个对象(该对象映射到数据库中表的一行)
几乎每个 Sequelize 方法都是异步的。
模型查询
使用嵌套数组来重命名属性:
Model.findAll({
attributes: ['foo', ['bar', 'baz'], 'qux'],
})
1
2
3
2
3
等同于:
SELECT foo, bar AS baz, qux FROM ...
1
使用 sequelize.fn 进行聚合:
Model.findAll({
attributes: [
'foo',
[sequelize.fn('COUNT', sequelize.col('hats')), 'n_hats'],
'bar'
]
});
1
2
3
4
5
6
7
2
3
4
5
6
7
等同于:
SELECT foo, COUNT(hats) AS n_hats, bar FROM ...
1
使用聚合函数时,必须为它提供一个别名,以便能够从模型中访问它。
也可以在attributes
中搭配include
或exclude
使用。
数据类型
列参数
WHERE 子句
使用
ORM 工具,映射到数据库,像操作对象一样去操作数据库。团队中一般不会直接写 sql 去操作数据库,而是使用 ORM 工具。
- 建模(外键) & 同步到数据库
- 增删改查 & 连表查询
- 数据表,用 JS 中的模型(class)代替
- 一条或多条记录,用 JS 中一个对象或数组代替
- sql 语句,用对象方法代替
安装使用
安装 sequelize:
yarn add sequelize
1
安装 mysql:
yarn add mysql2
1
连接数据库和建模
const Sequelize = require('sequelize')
const seq = new Sequelize('case2-microblog', 'root', '123456', {
host: 'localhost',
dialect: 'mysql',
})
seq
.sync({ force: true })
.then(() => {
process.exit()
})
.catch((error) => {
console.log('sync', error)
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
建模:
// 创建 User 模型,创建后的表名是users
const User = seq.define('user', {
// id 会自动创建,并设为主键、自增
userName: {
type: Sequelize.STRING, // varchar(255)
allowNull: false, // 不为空
unique: true, // 唯一性
},
password: {
type: Sequelize.STRING,
allowNull: false,
},
nickName: {
type: Sequelize.STRING,
comment: '昵称', // 注释
},
// 会自动创建`createdAt`和`updatedAt`
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
外键关联:
Blog.belongsTo(User, {
// 创建外键 Blog.userId -> User.id
foreignKey: 'userId',
})
// 另一种写法
User.hasMany(Blog, {
// 创建外键 Blog.userId -> User.id
foreignKey: 'userId',
})
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
创建记录
使用create
创建一条记录:
const userInfo = await User.create({
userName: 'licong',
password: '123456',
nickName: '阿聪',
})
console.log(userInfo.dataValues)
1
2
3
4
5
6
2
3
4
5
6
使用bulkCreate
创建多条记录:
const userInfo = await User.bulkCreate(
[
{
userName: 'licong',
password: '123456',
nickName: '阿聪',
},
{
userName: 'zhangsan',
password: '123456',
nickName: '张三',
},
],
{ returning: true }
)
// returning: true 返回结果信息
console.log(userInfo.dataValues)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
查询记录
- findOne
- findAll
- findAndCountAll
findOne
:
查询一条记录使用const licong = await User.findOne({
// attributes: ['userName', 'nickName'], // 查询特定的列
where: {
userName: 'licong',
},
})
console.log(licong.dataValues)
1
2
3
4
5
6
7
2
3
4
5
6
7
findAll
:
查询多条记录使用const blogs = await Blog.findAll({
where: {
userId: 1,
},
limit: 2, // 限制本次查询 2 条
offset: 1, // 跳过 1 条
order: [
['id', 'desc'], // 排序
],
})
console.log(blogs.map((blog) => blog.dataValues))
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
findAndCountAll
:
查询总数使用const blogListAndCount = await Blog.findAndCountAll({
where: {
userId: 1,
},
limit: 2,
offset: 1,
order: [
['id', 'desc'], // 排序
],
})
console.log(blogListAndCount.count) // 返回所有总条数
console.log(blogListAndCount.rows.map((blog) => blog.dataValues))
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
setDataValue 设置值
instance.setDataValue(key, value)
1
getDataValue 获取值
instance.getDataValue(key)
1
连表查询
查 Blog 表包含上 User 表:
const blogListWithUser = await Blog.findAndCountAll({
order: [['id', 'desc']],
include: [
{
model: User,
attributes: ['userName'],
where: {
userName: 'licong',
},
},
],
})
console.log(blogListWithUser.count)
console.log(
blogListWithUser.rows.map((blog) => {
const blogVal = blog.dataValues
blogVal.user = blogVal.user.dataValues
return blogVal
})
)
// 要使用这种方式外键关联
Blog.belongsTo(User, {
// 创建外键 Blog.userId -> User.id
foreignKey: 'userId',
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
查 User 表包含上 Blog 表:
const userListWithBlog = await User.findAndCountAll({
attributes: ['userName', 'nickName'],
include: [
{
model: Blog,
},
],
})
console.log(
userListWithBlog.rows.map((user) => {
const userVal = user.dataValues
// 每个用户有多条数据
userVal.blogs = JSON.stringify(userVal.blogs.map((blog) => blog.dataValues))
return userVal
})
)
// 要使用这种方式外键关联
User.hasMany(Blog, {
// 创建外键 Blog.userId -> User.id
foreignKey: 'userId',
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
模型(表)之间的关联关系
数据库中的表之间存在一定的关联关系,表之间的关系基于主/外
键进行关联、创建约束等。关系表中的数据分为1对1(1:1)
、1对多(1:M)
、多对多(N:M)
三种关联关系。
hasOne
: 添加外键到目标模,与目标模型建立1:1
关联关系,关联关系(外键)存在于目标模型
中。belongsTo
: 为当前模型添加外键,与目标模型建立1:1
关联关系,关联关系(外键)存在于源模型
中。hasMany
: 添加外键到目标模型,与目标模型建立1:N
关联关系,关联关系(外键)存在于目标模型
中。belongsToMany
: 与目标模型建立N:M
关联关系,会创建交叉表。
修改记录
修改一条记录使用update
:
const updateRes = await Blog.update(
{
title: '修改标题',
},
{
where: {
id: 1,
},
}
)
console.log(updateRes[0] > 0)
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
删除记录
删除一条记录使用destroy
:
const destroyRes = await Blog.destroy({
where: {
id: 1,
},
})
console.log(destroyRes > 0)
1
2
3
4
5
6
2
3
4
5
6
关联
Sequelize 提供了 四种 关联类型,并将它们组合起来以创建关联:
- HasOne 关联类型
- BelongsTo 关联类型
- HasMany 关联类型
- BelongsToMany 关联类型
关联的定义顺序是有关系的. 换句话说,对于这四种情况,定义顺序很重要. 在上述所有示例中,A 称为 源 模型
,而 B 称为 目标 模型
. 此术语很重要.
将 fooId 列添加到 Bar 中
Foo.hasOne(Bar)
Bar.belongsTo(Foo)
1
2
2
等同于:
CREATE TABLE IF NOT EXISTS "foos" (
/* ... */
);
CREATE TABLE IF NOT EXISTS "bars" (
/* ... */
"fooId" INTEGER REFERENCES "foos" ("id") ON DELETE SET NULL ON UPDATE CASCADE
/* ... */
);
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
自定义外键
// 方法 1
Foo.hasOne(Bar, {
foreignKey: 'myFooId',
})
Bar.belongsTo(Foo)
// 方法 2
Foo.hasOne(Bar, {
foreignKey: {
name: 'myFooId',
},
})
Bar.belongsTo(Foo)
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
其它用法
attributes
返回指定字段:
{
attributes: ['id', 'name', 'code']
}
1
2
3
2
3
排除指定字段:
{
attributes: {
exclude: ['createdAt', 'updatedAt', 'deletedAt']
}
}
1
2
3
4
5
2
3
4
5
有这两种用法就不需要再改写全局Model.prototype.toJSON
,但是两者不可同时使用。