sequelize 5.0中文文档 查询操作符和模型增删改查使用 (三) - node.js语言最好用的orm
文章目录
- 查询操作符
- 操作符使用
- OperatorsAliases操作符别名
- 模型增删改查
查询操作符
Sequelize提供了一整套查询操作符,下面分别列出来看下
比较操作符
const Op = Sequelize.Op
[Op.and]: {a: 5} // AND (a = 5)
[Op.or]: [{a: 5}, {a: 6}] // (a = 5 OR a = 6)
[Op.gt]: 6, // > 6
[Op.gte]: 6, // >= 6
[Op.lt]: 10, // < 10
[Op.lte]: 10, // <= 10
[Op.ne]: 20, // != 20
[Op.eq]: 3, // = 3
[Op.not]: true, // IS NOT TRUE
[Op.between]: [6, 10], // BETWEEN 6 AND 10
[Op.notBetween]: [11, 15], // NOT BETWEEN 11 AND 15
[Op.in]: [1, 2], // IN [1, 2]
[Op.notIn]: [1, 2], // NOT IN [1, 2]
[Op.like]: '%hat', // LIKE '%hat'
[Op.notLike]: '%hat' // NOT LIKE '%hat'
[Op.iLike]: '%hat' // ILIKE '%hat' (case insensitive) (PG only)
[Op.notILike]: '%hat' // NOT ILIKE '%hat' (PG only)
[Op.regexp]: '^[h|a|t]' // REGEXP/~ '^[h|a|t]' (MySQL/PG only)
[Op.notRegexp]: '^[h|a|t]' // NOT REGEXP/!~ '^[h|a|t]' (MySQL/PG only)
[Op.iRegexp]: '^[h|a|t]' // ~* '^[h|a|t]' (PG only)
[Op.notIRegexp]: '^[h|a|t]' // !~* '^[h|a|t]' (PG only)
[Op.like]: { [Op.any]: ['cat', 'hat']}
// LIKE ANY ARRAY['cat', 'hat'] - also works for iLike and notLike
[Op.overlap]: [1, 2] // && [1, 2] (PG array overlap operator)
[Op.contains]: [1, 2] // @> [1, 2] (PG array contains operator)
[Op.contained]: [1, 2] // <@ [1, 2] (PG array contained by operator)
[Op.any]: [2,3] // ANY ARRAY[2, 3]::INTEGER (PG only)
[Op.col]: 'user.organization_id'
范围操作符
** 注意,提供的范围值也可以定义边界的闭包,即[为闭口,(为开口**
[Op.contains]: 2 // @> '2'::integer (PG range contains element operator)
[Op.contains]: [1, 2] // @> [1, 2) (PG range contains range operator)
[Op.contained]: [1, 2] // <@ [1, 2) (PG range is contained by operator)
[Op.overlap]: [1, 2] // && [1, 2) (PG range overlap (have points in common) operator)
[Op.adjacent]: [1, 2] // -|- [1, 2) (PG range is adjacent to operator)
[Op.strictLeft]: [1, 2] // << [1, 2) (PG range strictly left of operator)
[Op.strictRight]: [1, 2] // >> [1, 2) (PG range strictly right of operator)
[Op.noExtendRight]: [1, 2] // &< [1, 2) (PG range does not extend to the right of operator)
[Op.noExtendLeft]: [1, 2] // &> [1, 2) (PG range does not extend to the left of operator)
操作符使用
const Op = Sequelize.Op;
{
score: {
[Op.or]: {
[Op.lt]: 95,
[Op.eq]: null
}
}
}
// score < 95 OR score IS NULL
// 查询分数小于95或者分数是NULL的记录
{
createdAt: {
[Op.lt]: new Date(),
[Op.gt]: new Date(new Date() - 24 * 60 * 60 * 1000)
}
}
// createdAt < [timestamp] AND createdAt > [timestamp]
创建时间小于现在 并且 大于前24小时的时间点
{
[Op.or]: [
{
url: {
[Op.like]: 'https://yijiebuyi.com%'
}
},
{
description: {
[Op.like]: '%sequelize%'
}
}
]
}
//url以 https://yijiebuyi.com开头 或者 描述中包含 sequelize 关键词的记录
OperatorsAliases操作符别名
注意:sequelize v5及以后更高版本不推荐使用别名
虽然sequelize内部允许指定的字符串作为操作符别名来使用:
const Op = Sequelize.Op;
const operatorsAliases = {
$gt: Op.gt
}
const connection = new Sequelize(db, user, pass, { operatorsAliases })
//初始化时指定operatorsAliases
这时 $gt: 95 等同于 Op.gt (> 95)
操作符安全性
不使用sequelize别名操作符,可以提供系统安全性,
如果你使用了sequelize别名操作符,而且用户的输入没有做过滤,直接在orm中使用,可能会被注入 sequelize对象或者运算符.
假如用户登录过程中,输入的用户名是
zhangzhi `id :{$gt: 0}`
而我们并没有对用户输入做过滤或者检查,直接提交给orm开始查找此用户,会被注入运算符.
官方提示如下:
向后兼容性原因Sequelize默认设置下面的别名 - $eq, $ne, $gte, $gt, $lte, $lt, $not, $in, $notIn, $is, $like, $notLike, $iLike, $notILike, $regexp, $notRegexp, $iRegexp, $notIRegexp, $between, $notBetween, $overlap, $contains, $contained, $adjacent, $strictLeft, $strictRight, $noExtendRight, $noExtendLeft, $and, $or, $any, $all, $values, $col
目前以下遗留别名也被设置,但计划在不久的将来被完全移除 - ne, not, in, notIn, gte, gt, lte, lt, like, ilike, $ilike, nlike, $notlike, notilike, .., between, !.., notbetween, nbetween, overlap, &&, @>, <@
所以不建议使用操作符别名,如果你一定要使用,可以设置operatorsAliases选项映射
const Op = Sequelize.Op;
const operatorsAliases = {
$eq: Op.eq,
$ne: Op.ne,
$gte: Op.gte,
$gt: Op.gt,
$lte: Op.lte,
$lt: Op.lt,
$not: Op.not,
$in: Op.in,
$notIn: Op.notIn,
$is: Op.is,
$like: Op.like,
$notLike: Op.notLike,
$iLike: Op.iLike,
$notILike: Op.notILike,
$regexp: Op.regexp,
$notRegexp: Op.notRegexp,
$iRegexp: Op.iRegexp,
$notIRegexp: Op.notIRegexp,
$between: Op.between,
$notBetween: Op.notBetween,
$overlap: Op.overlap,
$contains: Op.contains,
$contained: Op.contained,
$adjacent: Op.adjacent,
$strictLeft: Op.strictLeft,
$strictRight: Op.strictRight,
$noExtendRight: Op.noExtendRight,
$noExtendLeft: Op.noExtendLeft,
$and: Op.and,
$or: Op.or,
$any: Op.any,
$all: Op.all,
$values: Op.values,
$col: Op.col
};
const connection = new Sequelize(db, user, pass, { operatorsAliases });
这样的设置你可以继续使用操作符别名,但是系统会发送你一个警告:
Sequelize will warn you if you're using the default aliases and not limiting them if you want to keep using all default aliases (excluding legacy ones) without the warning you can pass the following operatorsAliases option
模型增删改查
基本覆盖常用的Sequelize的API
以下所有的API都是基于Sequelize Model的实例,示例中直接使用 Model 来表示 Model对应一个实例,如下:
Model.findAll => Blog.findAll
查询多条 findAll(options) 或者 all(options)
指定属性字段
Model.findAll({
attributes: ['title', 'content']
});
指定模型筛选字段 title 和 content
排除指定的表字段
Model.findAll({
attributes: {exclude:['id']}
});
指定模型排除字段 id
添加where查询条件
可以传递一个 where 对象来过滤查询.
where 通常用 attribute:value 键值对呈现,
其中 value 可以是匹配等式的数据或其他运算符的键值对象,也可以通过嵌套 or 和 and 运算符的集合来生成复杂的 AND/OR 条件
OR条件示例:
where: {
[Op.or]: [{author: 'yijiebuyi'}, {author: 'zhangzhi'}]
}
上面查询条件指定作者是 yijiebuyi 或者 zhangzhi
Model.findAll({
where:{
id:{[Op.gt]:10},//id大于10的
name:"yijiebuyi" //name等于yijiebuyi
},
attributes: ['title', 'content']
});
添加排序条件
排序默认升序排列
Model.findAll({
where:{
id:{[Op.gt]:10},//id大于10的
name:"yijiebuyi" //name等于yijiebuyi
},
order:[
"id", //根据id排序
["id","desc"]//根据id倒序
],
attributes: ['title', 'content']
});
添加分页条件
跳过10个实例
Model.findAll({ offset: 8 })
Model.findAll({
where:{
id:{[Op.gt]:10},//id大于10的
name:"yijiebuyi" //name等于yijiebuyi
},
order:[
"id", //根据id排序
["id","desc"]//根据id倒序
],
limit:10,//返回个数
offset:20,//起始位置,跳过数量,用于分页
attributes:["title","content"], //返回的字段
});
属性可以使用嵌套数组来重命名
Model.findAll({
where:{
id:{[Op.gt]:10},//id大于10的
name:"yijiebuyi" //name等于yijiebuyi
},
order:[
"id", //根据id排序
["id","desc"]//根据id倒序
],
limit:10,//返回个数
offset:20,//起始位置,跳过数量,用于分页
attributes:["title",["content":"cont"]], //返回的字段
});
上面返回字段是 title 和 cont, 其中表结构中的字段 content 被替换为 cont.
属性可以使用sequelize.fn来进行聚合
Model.findAll({
where:{
id:{[Op.gt]:10},//id大于10的
name:"yijiebuyi" //name等于yijiebuyi
},
order:[
"id", //根据id排序
["id","desc"]//根据id倒序
],
limit:10,//返回个数
offset:20,//起始位置,跳过数量,用于分页
attributes:["id","title",["content":"cont"],[sequelize.fn('COUNT', sequelize.col('id')), 'total_count']], //返回的字段
});
上面查询条件返回属性字段中,除了content字段被替换为 cont,
另外新增了聚合字段 total_count: 此字段并未数据结构中表字段,而是在查询结果集中使用orm的sequelize.fn函数来进行的聚合字段,
使用的聚合方法:COUNT ,对查询结果集中 id 字段进行 COUNT 聚合计算.
通过id查询findByPk(id,opts)
这里默认数据的主键是id,查询的时候直接通过id查询数据
const blogInfo = await Blog.findById(100);
查询一条记录findOne(opts)
根据条件查询记录,条件缺少时会返回第一条数据
const model = await Blog.findOne({
where:{id:100}
});
分页查询findAndCountAll(opts)
此api是我们对数据处理最常用的方法之一了
它默认执行了2条SQL语句
const data = await Blog.findAndCountAll({
limit:10,//每页10条
offset:x*10,//第x页(页码)*每页展示数量
where:{}
});
let list = data.rows;//list 数据集
let count = data.count;//数据总条数
对应执行的2条SQL
select count(*) from blogs where ...;
select a,b,c from blogs where .... limit 0,10;
添加新数据create(model,opts)
create 方法只需传入model对象即可,
如果model对象的属性和字段名不一致,就会出错.
const blogInfo= {
title:"博客标题",
content:"博客内容"
}
await Blog.create(blogInfo);
查询不存在就返回默认对象findOrBuild(opts)
findOrBuild(options)
- options.where 查询条件
- options.defaults 临时构建默认示例
当你的应用场景必须要返回值的时候,
这个方法可以满足你,根据条件去查询对象,
如果找不到就构建一个默认对象
注意:构建的对象不会保存到库中
查询不存在就创建对象findOrCreate(opts)
findOrCreate(options)
- options.where 查询条件
- options.defaults 创建新示例
和上一个不同的是,找不到实例后自动创建一个示例,并且保存到数据库.
upsert(model,opts)更新实例不存在就创建
根据主键或者唯一约束键匹配实例,
如果找不到实例,就创建
找到实例,就更新
upsert(model,option)
- model 要更新或者插入的对象
- option 可选
- options.validate 插入前验证
- options.fields 插入或者更新的字段数组,默认全部字段 如:['title','content']
- options.returning 只对postgresql有效 ,如果为true,则取回自动生成的值
省略不常用的选项参数,需要查看全部api,请移步官方文档:
https://sequelize.org/master/class/lib/model.js~Model.html#static-method-upsert
更新记录update(model,opts)
update(model,option)
- model 要更新的对象
- options 指定参数
- where 指定搜索范围的选项
- fields 数组,指定要更新的字段,默认全部字段
- validate true表示插入每一行前进行验证,如果其中一行未通过验证,全部插入操作都失败
- returning 仅适用于postgresql, true 表示返回更新的对象
- limit 更新多少行,仅适用于 mysql和mariadb
- silent 为true时,updateAt 时间戳不会更新
删除记录destroy(opts)
删除有2种情况,一种是物理删除。删除就从表中不存在了.
另外一种就是设置paranoid,这个是虚拟删除 ,如果开启 paranoid ,删除操作会把 deleteAt字段更新为当前时间来做标记删除.
destroy(option)
- option.where 删除的范围
- option. limit 删除多少行
- option.force 布尔值,默认false ,当启用 paranoid 时,此选项为true时,将不会更新deleteAt时间戳,而是直接删除