本篇主要介绍nodejs中的orm框架 —> Sequelize
概述
基于Promise的ORM(Object Relation Mapping),是一种数据库中间件支持多种数据库、事务、关联等
中间件是介于应用系统和系统软件之间的一类软件,它使用系统软件所提供的基础服务(功
能),衔接网络上应用系统的各个部分或不同的应用,能够达到资源共享、功能共享的目的。目前,它并没有很严格的定义,但是普遍接受IDC的定义:中间件是一种独立的系统软件服务程序,分布式应用软件借助这种软件在不同的技术之间共享资源,中间件位于客户机服务器的操作系统之上,管理计算资源和网络通信。从这个意义上可以用一个等式来表示中间件:中间件=平台+通信,这也就限定了只有用于分布式系统中才能叫中间件,同时也把它与支撑软件和实用软件区分开来。
安装
1 | npm i sequelize mysql2 -S |
orm和sql的对照关系
sql | orm |
---|---|
select | findAll(查询多条 ),findOne(获取第一个条目 ),findByPk(findById不支持了 ),findOrCreate(查询,不存在就新建一个 ),findAndCountAll(分页查询/查询多条并统计数量 ) |
update | update |
insert | create |
delete | destroy |
数据类型
orm | sql |
---|---|
Sequelize.STRING | VARCHAR(255) |
Sequelize.STRING(1234) | VARCHAR(1234) |
Sequelize.TEXT | TEXT |
Sequelize.TEXT(‘tiny’) | TINYTEXT |
Sequelize.CITEXT | CITEXT 仅 PostgreSQL 和 SQLite. |
Sequelize.TSVECTOR | TSVECTOR 仅 PostgreSQL. |
Sequelize.BOOLEAN | TINYINT(1) |
Sequelize.INTEGER | INTEGER |
Sequelize.BIGINT | BIGINT |
Sequelize.BIGINT(11) | BIGINT(11) |
Sequelize.FLOAT | FLOAT |
Sequelize.FLOAT(11) | FLOAT(11) |
Sequelize.FLOAT(11, 10) | FLOAT(11,10) |
Sequelize.REAL | REAL 仅 PostgreSQL. |
Sequelize.REAL(11) | REAL(11) 仅 PostgreSQL. |
Sequelize.REAL(11, 12) | REAL(11,12) 仅 PostgreSQL. |
Sequelize.DOUBLE | DOUBLE |
Sequelize.DOUBLE(11) | DOUBLE(11) |
Sequelize.DOUBLE(11, 10) | DOUBLE(11,10) |
Sequelize.DATE | DATETIME 适用于 mysql / sqlite, 带时区的TIMESTAMP 适用于 postgres |
Sequelize.DATE(6) | DATETIME(6) 适用于 mysql 5.6.4+. 支持6位精度的小数秒 |
Sequelize.DATEONLY | 不带时间的 DATE |
前期准备
建立连接
1
2
3
4
5
6
7
8
9
10
11
12
13const Sequelize = require('sequelize')
const sequelize = new Sequelize(db.database, db.user, db.password, { //表名 用户名 密码
host: db.host, //地址
port: db.port, //端口
dialect: 'mysql', //数据库类型:'mysql'|'mariadb'|'sqlite'|'postgres'|'mssql'
pool: { // 连接池配置
max: 5,
min: 0,
acquire: 30000,
idle: 10000,
},
timezone: '+08:00' //时区转换
})定义模型
1
2
3
4
5
6
7
8
9
10
11
12
13
14const User = sequelize.define('user',{
id: {
type: Sequelize.STRING(255),
primaryKey: true, //主键
autoIncrement: true, // 自增长
allowNull:false
},
name: {
type: Sequelize.STRING,
defaultValue: 'name1', //设置默认值
comment: "姓名" //注释
}
role: Sequelize.INTEGER(11),
})同步数据库
1
2
3
4
5// 严重:force := true 会强制删除表及数据后重建,请一定慎用!!!
User.sync({ force: false }).then(() => {});
// 强制同步:创建表之前先删除已存在的表
User.sync({ force: true }).then(() => {});避免自动生成时间戳字段
1
2
3const User = sequelize.define('user',{},{
timestamps:false
})指定表名
- freezeTableName:true
- tableName:’xxx’
前者以modelName作为表名,后者则按其值作为表名
蛇形命名 underscored:true
默认驼峰 命名
- 实例用法
- 更新
1
2
3
4
5
6const jane = await User.create({ name: "Jane" });
console.log(jane.name); // "Jane"
jane.name = "Ada";
// 数据库中的名称仍然是 "Jane"
await jane.save();
// 现在该名称已在数据库中更新为 "Ada"! - 删除
1
2
3
4const jane = await User.create({ name: "Jane" });
console.log(jane.name); // "Jane"
await jane.destroy();
// 现在该条目已从数据库中删除 - 重载
1
2
3
4
5
6const jane = await User.create({ name: "Jane" });
console.log(jane.name); // "Jane"
jane.name = "Ada";
// 数据库中的名称依然是 "Jane"
await jane.reload();
console.log(jane.name); // "Jane"reload 调用生成一个 SELECT 查询,以从数据库中获取最新数据.
UUID
1
2
3
4
5
6
7id: {
type: Sequelize.UUID,
primaryKey: true, //主键
autoIncrement: true, // 自增长
allowNull:false,
defaultValue: Sequelize.UUIDV1,
}Getters & Setters
1 | // 定义为属性的一部分 |
基本增删改查
增
1
2
3
4
5const res = User.create({
name:"joker",
role:1
})
consoole.log('create',res)改
1
2
3
4
5const res = User.update(
{role:2},
{where:{id:1}}
)
consoole.log('update',res)查
- 单条
1
2
3
4
5
6
7
8
9
10User.findOne({
attributes: ['id', 'name', 'role'], // 指定需要返回的字段
where: {
id: id
}
}).then(result => {
console.log(result)
}).catch(err => {
console.log(err)
}); - 多条
1
2
3
4
5
6const Op = Sequelize.Op
const res = User.findAll(
{where:{role:{[Op.lt]:3,[Op.gt]:1}}}
)
consoole.log('findAll',res)
- 单条
删
- 方式1
1
2
3
4
5
6
7
8
9User.destroy({
where: {
id: 1
}
}).then(result => {
console.log(result)
}).catch(err => {
console.log(err)
}); - 方式2
1
2
3
4
5
6
7
8
9User.findOne({
where: {
id: 1
}
}).then(result => {
result.destroy()
}).catch(err => {
console.log(err)
});
- 方式1
进阶用法
查询特定属性
1 | Model.findAll({ |
可以使用嵌套数组来重命名属性
1 | Model.findAll({ |
添加聚合
1 | // 获取帽子数量 |
排除某些属性
1 | Model.findAll({ |
分页查询
1 | Model.findAndCountAll({ |
查询,不存在就新建一个
1 | Model.findOrCreate({ |
批量新增
1 | const data = [{id: 1, name: '张三'}, {id: 1, name: '李四'}] |
排序
1 | Model.findAll({ |
DESC表示降序,默认ASC升序
更多用法
实用方法
count
1
2
3
4
5
6
7
8const num = await User.count({
where: {
age: {
[Op.gt]: 25
}
}
});
// 统计年龄大于25的人数max, min
1
2
3await User.max('age'); // 最大年龄
await User.min('age'); // 最小年龄
await User.min('age', { where: { age: { [Op.gt]: 5 } } }); // 大于五岁的最小年龄sum
1
2await User.sum('age'); // 年龄总和
await User.sum('age', { where: { age: { [Op.gt]: 5 } } }); // 大于五岁的年龄总和
关联查询
一对一
1 | ModelA.belongsTo(ModelB,{ |
一对多
1 | ModelA.belongsTo(ModelB) |
多对多
1 | ModelA.belongToMany(ModelB) |
常用符号运算符
1 | [Op.eq]: 3, // = 3 |
一些踩过的坑
在查询结果中添加自定义属性
1 | rlt.rows[i] =rlt.rows[i].toJSON() // 先进行toJSON 操作 然后才能赋值 |