查询条件和通配符
- 大于:$gt [greater than]
- 小于:$lt [less than]
- 大于等于:$ge [greater equal]
- 小于等于:$le [less equal]
- 等于:$eq
- 不等于:$ne [not]
- 包含:$in
- 不包含: $nin
- 并且:$and
- 反转查询,返回不满足指定条件的文档:$not
- 或者: $or
- 不满足数组中指定的所有条件:$nor
- 正则表达式:$regex 也可以用字面量//来简写
- 增减修改器,只对数字有效:$inc
- 设置键:$set
- 删除键:$unset
- 向数组添加:$push
- 向数组中添加元素,存在就不添加:$addToSet
- 遍历数组:$each
- 向数组中尾部删除一个元素:$pop
- 向数组中删除指定元素:$pull
- sort:排序 1 正序 -1 倒叙
- skip:指定忽略条数
- limit:限定返回的最大条数
find 九分是查找一分增删改
Model.find(query,filter,options,callback)
- query: 查询条件
- filter:对查询出来的数据进行过滤 默认
+
就是让数据只显示过滤部分数据,-
从数据中抹去部分数据 - options:比如排序,截取等操作
- callback:执行函数,得到返回数据,因 find 是 promise,所以可用 then 替代。
query 查询条件
大于小于举例子
大于:查找年龄大于 5 岁的
UserModel.find({ age: { $gt: 5 } })
小于:查找年龄小于 5 岁的
UserModel.find({ age: { $lt: 5 } })
大于 5,小于 10
UserModel.find({ age: { $gt: 5, $lt: 10 } })
$in 包含
UserModel.find({ age: { $in: [5, 6, 7] } })
$or 或者
可以多个条件
UserModel.find({
$or: [{ name: "songyu2" }, { age: 5 }],
});
2
3
嵌套对象字段的查找
数据如下
{
name: { first: "dora", last: "wang" }
}
2
3
使用点语法,可匹配嵌套的字段,其中字段名必须用引号引起来。
Model.find({ "name.last": "wang" });
数组查找
假数据
{
year: [2018, 2019];
}
{
year: [2017, 2019, 2020];
}
{
year: [2016, 2020];
}
2
3
4
5
6
7
8
9
- $all 匹配包含查询数组中指定的所有条件的数组字段
- $elemMatch 匹配数组字段中的某个值满足 $elemMatch 中指定的所有条件
- $size 匹配数组字段的 length 与指定的大小一样的 document
查找数组中的至少一个值:可使用精确查找写法 {field: value}
查找数组中的多个值:使用 $all 查找同时存在 2019 和 2020 的 document Model.find({ year: { $all: [ 2019, 2020 ] } });
$elemMatch 单个字段值满足所有查询条件:$elemMatch 查找数组字段中的值同时满足所有条件的 document。 Model.find({ year: { $elemMatch: { $gt: 2016, $lt: 2018 } } })
数组下标查询,同对象点查找语法一致:Model.find({ 'year.1': { $gt: 2019 } })
数组对象的查找
假数据
{
author: [
{ name: "dora", age: 18 },
{ name: "wang", age: 16 },
];
}
2
3
4
5
6
精确查询
精确匹配,顺序、字段都必须一致。 Model.find({ author: { name: "dora", age: 18 } })
点语法查询Model.find({ 'author.age': { $gte: 18 } })
$elemMatch 同时满足所有查询条件Model.find({ "author": {$elemMatch: {name: 'dora', age:{ $lt: 18 }}})
查询 id
专用的方法是 Model.findById('xxx')
也可以 Model.find({ _id: 1 })
,但不推荐
正则模糊查询
userModel.find({"name" : {$regex:'大虾'}})
userModel.find({"name" : /大虾/ }})
2
3
$exists 找非空内容
false 查询不存在该字段的文档,true 查询存在该字段的文档
Model.find({ name: { $exists: true } }, function(error, docs) {
//查询所有存在name属性的文档
});
Model.find({ telephone: { $exists: false } }, function(error, docs) {
//查询所有不存在telephone属性的文档
});
2
3
4
5
6
7
filter 过滤
解读
指定要包含或排除哪些 document 字段(也称为查询“投影”),必须同时指定包含或同时指定排除,不能混合指定,_id 除外。
在 mongoose 中有两种指定方式,字符串指定和对象形式指定。
字符串指定时在排除的字段前加 - 号,只写字段名的是包含。
如果有多个要包含或排除的值用空格隔开
Model.find({}, "age");
Model.find({}, "-name");
2
对象形式指定时,1 是包含,0 是排除。
Model.find({}, { age: 1 });
Model.find({}, { name: 0 });
2
还可以使用使用 select() 方法定义
Model.find({}).select("name age");
Model.find({}).select({ name: 0 });
2
options 选项
导读
它的作用就是帮助我们进行数据的高级操作,比如排序等等
有三种方式实现
Model.find(filter,null,options)
Model.find(filter).setOptions(options)
Model.find(filter).<option>(xxx)
2
3
options 选项见官方文档 Query.prototype.setOptions()open in new window。
这里列出常用的几个
- sort:按照排序规则根据所给的字段进行排序,值可以是 asc, desc, ascending, descending, 1, 和 -1。
- limit:指定返回结果的最大数量
- skip:指定要跳过的文档数量
- lean:返回普通的 js 对象,而不是 Mongoose Documents。建议不需要 mongoose 特殊处理就返给前端的数据都最好使用该方法转成普通 js 对象。
sort 三种方式指定排序
// 这是第三种写法,可以链式调用
// 字符串有 - 代表 descending 降序
Model.find({}).sort("age -name");
Model.find({}).sort({ age: "asc", name: -1 });
// 第一种写法,参数二如果没有,必须给个空占位
Model.find({}, null, { sort: { name: -1 } });
2
3
4
5
6
分页小例子
以下代码里使用的 skip,limit,sort 执行顺序无论怎么写都是:先 sort 再 skip,最后 limit
如果没有 sort,先看 skip 和 limit, 当两者一起使用的时候, 不管其位置顺序,默认先 skip,再 limit。
// 分页查询 每页3条,查询第2页
(async function() {
let pageSize = 3;
let pageNumber = 1;
// sort是根据条件进行排序,1正序-1倒序;
// skip指定忽略条数;limit限定返回的最大条数
const data = await UserModel.find({})
.sort({ age: 1 })
.skip((pageNumber - 1) * pageSize)
.limit(pageSize);
console.log(data);
})();
2
3
4
5
6
7
8
9
10
11
12
aggregate 管道流
上面的分页小例子,我们可以看出执行顺序,但如果我们想要先跳过,再限制条数 最后才排序怎么办?
可以用 aggregate, aggregate 有管道流的性质,$skip,$limit,$sort 执行顺序跟位置一致。
Model.find({}).aggregate({ $skip: 2 }, { $sort: 3 });
callback 执行结果
传入
Mongoose 中所有传入 callback 的查询,其格式都是 callback(error, result) 这种形式。如果出错,则 error 是出错信息,result 是 null;如果查询成功,则 error 是 null, result 是查询结果,查询结果的结构形式是根据查询方法的不同而有不同形式的。
find() 方法的查询结果是数组,即使没查询到内容,也会返回 [] 空数组。
不传
不传入 callback 时,查询方法返回的是一个 Query 实例,实例继承了 Query 原型 上的所有方法,因此返回的实例可以链式调用其它方法,从而组成查询链。
let query = Model.find({ name: "Dora" });
query.select("name age -_id");
2
3
查询方法不传入回调函数时,获取查询数据的方式有两种:
1. exec()
使用 query 实例的 exec() 方法执行查询,即在链式语法的最后统一通过传入 callback 获取查询数据。
// 效果一样
Model.find(
{ name: /Dora/, age: { $gte: 16, $lt: 18 } },
'name age -_id',
{ limit: 2, sort: 'age' },
(err,res)=>{
if (err) return handleError(err);
console.log(res);
}
});
let query = Model.
find({ name: /Dora/ }).
where('age').gte(16).lt(18).
select('name age -_id').
limit(2).sort('age');
query.exec((err, res)=> {
if (err) return handleError(err);
console.log(res);
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2. then()
使用 query 实例的 then() 方法将查询链当作 promise 来处理。
query.then(
(res) => {
console.log(res);
},
(err) => {
console.log(err);
}
);
2
3
4
5
6
7
8
使用 async / await 获取查询结果。
let res = await query;
console.log(res);
2
修改器和更新器【数组】
更新修改器:
- ‘$inc’ 增减修改器,只对数字有效.下面的实例: 找到 age=22 的文档,修改文档的 age 值自增 1
Model.updateOne({‘age’:22}, {’$inc’:{‘age’:1} } ); 执行后: age=23
- ‘$set’ 指定一个键的值,这个键不存在就创建它.可以是任何 MondoDB 支持的类型.
Model.updateOne({‘age’:22}, {’$set’:{‘age’:‘haha’} } ); 执行后: age=‘haha’
- ‘$unset’ 同上取反,删除一个键
Model.updateOne({‘age’:22}, {’$unset’:{‘age’:‘haha’} } ); 执行后: age键不存在
数组修改器:
- ‘$push’ 给一个键 push 一个数组成员,键不存在会创建
Model.update({‘age’:22}, {’$push’:{‘array’:10} } ); 执行后: 增加一个 array 键,类型为数组, 有一个成员 10
- ‘$addToSet’ 向数组中添加一个元素,如果存在就不添加
Model.update({‘age’:22}, {’$addToSet’:{‘array’:10} } ); 执行后: array中有10所以不会添加
- ‘$each’ 遍历数组, 和 $push 修改器配合可以插入多个值
Model.update({‘age’:22}, {’$push’:{‘array’:{’$each’: [1,2,3,4,5]}} } ); 执行后: array : [10,1,2,3,4,5]
- ‘$pop’ 向数组中尾部删除一个元素
Model.update({‘age’:22}, {’$pop’:{‘array’:1} } ); 执行后: array : [10,1,2,3,4] tips: 将1改成-1可以删除数组首部元素
- ‘$pull’向数组中删除指定元素:
Model.update({‘age’:22}, {’$pull’:{‘array’:10} } ); 执行后: array : [1,2,3,4] 匹配到array中的10后将其删除
批量插入数据
const list = [];
for (let i = 1; i <= 10; i++) {
list.push({
name: `songyu${i}`,
_id: i,
age: i,
});
}
UserModel.create(list);
2
3
4
5
6
7
8
9
then 和 exec
两者返回的都是 promise 对象,而 mongoose 是自己封装的 promise。 exec 一般用于独立的动作一次性执行, then 则用于连续性的动作
从其方法名也可以区别它们的用法,exec 就是执行的意思, then 就是然后怎么怎么,
exec 和 then 的参数是有所不同的,前者是 callback(err,doc),后者则是 resolved(doc),rejected(err)
后续整理
- $or 或关系
- $nor 或关系取反
- $gt 大于
- $gte 大于等于
- $lt 小于
- $lte 小于等于
- $ne 不等于
- $in 在多个值范围内
- $nin 不在多个值范围内
- $all 匹配数组中多个值
- $regex 正则,用于模糊查询
- $size 匹配数组大小
- $maxDistance 范围查询,距离(基于 LBS)
- $mod 取模运算
- $near 邻域查询,查询附近的位置(基于 LBS)
- $exists 字段是否存在
- $elemMatch 匹配内数组内的元素
- $within 范围查询(基于 LBS)
- $box 范围查询,矩形范围(基于 LBS)
- $center 范围醒询,圆形范围(基于 LBS)
- $centerSphere 范围查询,球形范围(基于 LBS)
- $slice 查询字段集合中的元素(比如从第几个之后,第 N 到第 M 个元素