查询条件和通配符

  • 大于:$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 }],
});
1
2
3

嵌套对象字段的查找

数据如下

{
  name: { first: "dora", last: "wang" }
}
1
2
3

使用点语法,可匹配嵌套的字段,其中字段名必须用引号引起来。

Model.find({ "name.last": "wang" });
1

数组查找

假数据

{
  year: [2018, 2019];
}
{
  year: [2017, 2019, 2020];
}
{
  year: [2016, 2020];
}
1
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 },
  ];
}
1
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" : /大虾/ }})
1
2
3

$exists 找非空内容

false 查询不存在该字段的文档,true 查询存在该字段的文档

Model.find({ name: { $exists: true } }, function(error, docs) {
  //查询所有存在name属性的文档
});

Model.find({ telephone: { $exists: false } }, function(error, docs) {
  //查询所有不存在telephone属性的文档
});
1
2
3
4
5
6
7

filter 过滤

解读

指定要包含或排除哪些 document 字段(也称为查询“投影”),必须同时指定包含或同时指定排除,不能混合指定,_id 除外。

在 mongoose 中有两种指定方式,字符串指定和对象形式指定。

字符串指定时在排除的字段前加 - 号,只写字段名的是包含。
如果有多个要包含或排除的值用空格隔开

Model.find({}, "age");
Model.find({}, "-name");
1
2

对象形式指定时,1 是包含,0 是排除。

Model.find({}, { age: 1 });
Model.find({}, { name: 0 });
1
2

还可以使用使用 select() 方法定义

Model.find({}).select("name age");
Model.find({}).select({ name: 0 });
1
2

options 选项

导读

它的作用就是帮助我们进行数据的高级操作,比如排序等等

有三种方式实现

Model.find(filter,null,options)
Model.find(filter).setOptions(options)
Model.find(filter).<option>(xxx)
1
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 } });
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);
})();
1
2
3
4
5
6
7
8
9
10
11
12

aggregate 管道流

上面的分页小例子,我们可以看出执行顺序,但如果我们想要先跳过,再限制条数 最后才排序怎么办?

可以用 aggregate, aggregate 有管道流的性质,$skip,$limit,$sort 执行顺序跟位置一致。

Model.find({}).aggregate({ $skip: 2 }, { $sort: 3 });
1

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");
1
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);
  });
1
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);
  }
);
1
2
3
4
5
6
7
8

使用 async / await 获取查询结果。

let res = await query;
console.log(res);
1
2

修改器和更新器【数组】

更新修改器:

  1. ‘$inc’ 增减修改器,只对数字有效.下面的实例: 找到 age=22 的文档,修改文档的 age 值自增 1
Model.updateOne({‘age’:22}, {’$inc’:{‘age’:1} } ); 执行后: age=23
1
  1. ‘$set’ 指定一个键的值,这个键不存在就创建它.可以是任何 MondoDB 支持的类型.
Model.updateOne({‘age’:22}, {’$set:{‘age’:‘haha’} } ); 执行后: age=‘haha’
1
  1. ‘$unset’ 同上取反,删除一个键
Model.updateOne({‘age’:22}, {’$unset’:{‘age’:‘haha’} } ); 执行后: age键不存在
1

数组修改器:

  1. ‘$push’ 给一个键 push 一个数组成员,键不存在会创建
Model.update({‘age’:22}, {’$push’:{‘array’:10} } ); 执行后: 增加一个 array 键,类型为数组, 有一个成员 10
1
  1. ‘$addToSet’ 向数组中添加一个元素,如果存在就不添加
Model.update({‘age’:22}, {’$addToSet’:{‘array’:10} } ); 执行后: array中有10所以不会添加
1
  1. ‘$each’ 遍历数组, 和 $push 修改器配合可以插入多个值
Model.update({‘age’:22}, {’$push’:{‘array’:{’$each’: [1,2,3,4,5]}} } ); 执行后: array : [10,1,2,3,4,5]
1
  1. ‘$pop’ 向数组中尾部删除一个元素
Model.update({‘age’:22}, {’$pop’:{‘array’:1} } ); 执行后: array : [10,1,2,3,4] tips:1改成-1可以删除数组首部元素
1
  1. ‘$pull’向数组中删除指定元素:
Model.update({‘age’:22}, {’$pull’:{‘array’:10} } ); 执行后: array : [1,2,3,4] 匹配到array中的10后将其删除
1

批量插入数据

const list = [];
for (let i = 1; i <= 10; i++) {
  list.push({
    name: `songyu${i}`,
    _id: i,
    age: i,
  });
}
UserModel.create(list);
1
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 个元素

借鉴自:
Dora36open in new windowjayruanopen in new window

Last Updated:
Contributors: websong