条件、排序、分页和投影

本节学习更接近真实接口的查询。

一、比较查询

查询年龄大于等于 18 的用户:

db.users.find({
  age: { $gte: 18 }
})

常见比较操作符:

操作符含义
$gt大于
$gte大于等于
$lt小于
$lte小于等于
$ne不等于
$in在指定数组中
$nin不在指定数组中

示例:

db.users.find({
  status: { $in: ["active", "pending"] }
})

二、多个条件

多个字段默认就是 AND:

db.users.find({
  status: "active",
  age: { $gte: 18 }
})

表示:

status = active 并且 age >= 18

三、OR 查询

db.users.find({
  $or: [
    { username: "zhangsan" },
    { email: "zhangsan@example.com" }
  ]
})

适合登录时用户名或邮箱二选一查询。

四、排序

按创建时间倒序:

db.posts.find().sort({
  createdAt: -1
})
含义
1升序
-1降序

按年龄升序,再按创建时间倒序:

db.users.find().sort({
  age: 1,
  createdAt: -1
})

五、分页

第一页,每页 10 条:

db.posts.find()
  .sort({ createdAt: -1 })
  .skip(0)
  .limit(10)

第二页:

db.posts.find()
  .sort({ createdAt: -1 })
  .skip(10)
  .limit(10)

计算公式:

skip = (page - 1) * pageSize

数据量很大时,深分页 skip 会越来越慢。后续可以使用基于游标的分页,例如按 createdAt_id 继续查询。

六、投影

只返回需要的字段:

db.posts.find(
  { status: "published" },
  { title: 1, author: 1, createdAt: 1 }
)

排除内容字段:

db.posts.find(
  {},
  { content: 0 }
)

接口列表页通常不返回正文大字段,只返回标题、摘要、作者和时间。

七、正则查询

查询标题包含 MongoDB 的文章:

db.posts.find({
  title: /MongoDB/
})

正则查询要谨慎使用。

如果对大集合做无索引正则查询,可能非常慢。搜索功能更复杂时,可以考虑全文索引或专门搜索引擎。