首页/数据/NoSQL 速查/find 条件查询与投影
MongoDB99 条

find 条件查询与投影

find(filter, projection) 返回游标:filter 支持嵌套字段与各类操作符,projection 控制返回字段(默认总是带 _id)。

NoSQL 速查数据更新于 2026-10-13

find 是什么

find 是 MongoDB 的文档查询入口:db.collection.find(filter, projection) 在集合上做条件过滤加字段投影,返回游标(cursor)。语义上对应 SQL 的 SELECT ... WHERE,但条件用 BSON 文档表达,天然支持嵌套字段、数组元素、正则与多种查询操作符。它是使用频率最高的读操作,count 与聚合管道里的 $match 都共用同一套条件语法。

基本信息

适用版本MongoDB 3.2 及以上;mongosh 2.x
语法db.collection.find(filter, projection)
返回值游标,链式调用或迭代时才真正取数
权限对应库的 read / readWrite 角色
默认行为结果含 _id,mongosh 交互环境打印前 20 条

典型使用场景

  • 按主键或唯一键取单条记录,替代逐条遍历
  • 列表页多条件筛选:状态、时间区间、归属人组合
  • 导出或批处理:配合 sort 与 limit 分批拉取大集合
  • 排查数据问题:用投影只看关键字段,缩小输出体积
  • 执行更新前采样:先 find 确认真实命中范围与文档结构
  • 预演聚合逻辑:先用 find 验证 $match 条件是否写对

最小示例

最小示例
db.orders.find({ status: "paid", qty: { $gte: 2 } })        # 状态已支付且数量不小于 2
db.orders.find({ "customer.city": "Hangzhou" })             # 点号路径访问嵌套字段
db.orders.find({ tags: "vip" })                               # 数组字段:任一元素等于 vip
db.orders.find({ sku: { $in: ["A-1", "A-2"] } })              # 多值任一命中
db.orders.find({ ts: { $gte: ISODate("2026-01-01T00:00:00Z") } })
db.orders.find({}, { sku: 1, qty: 1, _id: 0 })                 # 只返回 sku 与 qty
db.orders.find().sort({ ts: -1 }).limit(10)                    # 最近 10 条

常用查询操作符

操作符含义写法示例
$eq / $ne等于 / 不等于{ status: { $ne: "void" } }
$gt $gte $lt $lte数值与日期比较{ qty: { $gt: 1, $lte: 9 } }
$in / $nin在 / 不在给定集合{ sku: { $in: ["A-1", "A-2"] } }
$exists字段是否存在{ remark: { $exists: true } }
$regex正则匹配,未锚定即子串匹配{ sku: /^A-/ }
$and / $or / $nor逻辑组合{ $or: [ { a: 1 }, { b: 1 } ] }
$elemMatch数组内多条件同时满足{ items: { $elemMatch: { sku: "A-1", qty: { $gt: 3 } } } }

投影与游标控制

投影与游标控制
db.orders.find({ status: "paid" }, { sku: 1, qty: 1, _id: 0 })   # 白名单投影
db.orders.find({ status: "paid" }, { items: 0 })                  # 黑名单投影:排除字段
const c = db.orders.find({ status: "paid" }).batchSize(200)        # 每批取 200 条
while (c.hasNext()) { printjson(c.next()) }                        # 手动迭代游标
find() 只构造游标、不发送请求;mongosh 交互环境在回车时自动迭代前 20 条,脚本里必须显式 toArray() 或循环迭代才会取数。
投影的指定字段与排除字段不能混用(只有 _id 例外);只取需要的字段能明显减少网络传输,但对磁盘读取量影响有限。
无过滤条件的 find() 等价于把整个集合拉回客户端,务必配合条件或 limit 使用;宁可先 count 确认规模再决定读法。
集合不存在时 find 返回空结果而不是报错;怀疑查错库表时用 show collections 与 db.getCollectionNames() 核对命名空间。

查询性能要点

  • 条件字段与索引前缀一致时才能用上索引,复合索引的字段顺序要与查询字段对齐
  • 只需要索引内字段时构成覆盖查询,无需回读文档,是速度最快的一类查询
  • 排序字段没有匹配索引时会走内存排序,大结果集上开销明显
  • 用 hint() 可以强制指定索引,验证执行计划差异时很有用
  • 把高选择性条件(唯一键、时间范围)放前面,能更快缩小候选集
  • 用 explain 观察 totalDocsExamined 与 nReturned 的比值,比值接近 1 才算高效

验证查询计划

验证查询计划
db.orders.find({ status: "paid" }).explain("executionStats")   # 看 winningPlan 与扫描量
db.orders.find({ sku: "A-1" }).hint({ sku: 1 })               # 强制走指定索引
db.orders.find({ sku: "A-1" }, { _id: 0, sku: 1 }).explain()  # 检查是否覆盖查询
find 条件里字段的书写顺序不影响索引选择,但复合索引的字段顺序必须与查询用到的字段前缀一致,否则只能部分利用索引。
对同一字段同时写 $gt 与 $lt 属于范围查询,复合索引中范围字段之后的字段通常无法再用于索引过滤,设计索引时把等值条件字段放前面。
同一集合内各文档结构可以不同,查询条件只会命中含该字段的文档;当统计口径依赖某字段时先核对字段覆盖率,别把缺失字段当成 0 处理。

易错点

  • 无参数 find() 会逐条拉回整个集合:千万级集合上直接拖垮客户端内存与带宽,先加条件再考虑 sort/limit
  • 对字符串形式数字用 $gte/$lte 是按二进制序比较,"10" 小于 "9",涉及大小比较的字段必须存成数值类型
  • 正则未用 ^ 锚定且没有前缀可用时无法借索引,集合大时要评估改用 text 索引或拆出可索引字段
  • 投影里 _id 默认返回,以为只输出指定字段会让结果多一列,需要时显式写 _id: 0
  • 对数组字段直接写 { items: { sku: "A-1", qty: 3 } } 会跨元素匹配,成组条件必须用 $elemMatch

数据来源与参考

  • MongoDB Manual: db.collection.find()
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌