MongoDB提供了两套常用的数据读取手段:一套是传统的find查询命令,另一套是基于聚合框架的aggregate管道。不少刚接触MongoDB的朋友会把它们当成互相替代的关系,其实两者定位并不相同。find负责单表的过滤与投影,胜在简单高效;聚合管道则像一条流水线,可以把过滤、分组、排序、关联等多个阶段串起来处理。本文围绕这两个命令展开,先讲透find的用法,再进入聚合管道的世界,最后对比它们的差异与适用场景。

find查询命令的核心用法
db.collection.find(query, projection)是MongoDB使用频率最高的命令,第一个参数指定查询条件,第二个参数控制返回哪些字段。当两个参数都省略时,find()会返回集合中的全部文档。查询条件使用字段名加值的键值对形式,例如{name: "张三"},也可以结合条件运算符实现范围查询。
条件运算符以$开头,常见的有$gt(大于)、$lt(小于)、$in(包含于列表)、$ne(不等于)等。多个条件默认是AND关系,需要OR关系时用$or包裹一个条件数组。投影参数里,1表示返回该字段,0表示排除该字段,但包含和排除不能混用,_id字段是唯一的例外。
// 查询年龄大于25且城市为北京或上海的用户,只返回姓名和年龄
db.users.find(
{ age: { $gt: 25 }, city: { $in: ["北京", "上海"] } },
{ name: 1, age: 1, _id: 0 }
)
// 使用 $or 实现"或"条件
db.users.find({
$or: [{ age: { $lt: 18 } }, { status: "inactive" }]
})
// 配合 sort、skip、limit 实现分页
db.users.find({ city: "北京" }).sort({ age: -1 }).skip(10).limit(10)find还支持链式调用sort()、skip()、limit()来完成排序和分页。需要注意的是,skip在数据量大时会随着跳过条数增加而变慢,深分页场景建议改用基于游标条件的写法,比如记住上一页最后一条记录的排序值,用它作为下一页的查询条件。
聚合管道aggregate的工作机制
聚合管道把数据处理拆分成一个个阶段(stage),文档像物料一样依次流过每个阶段被加工。常用的阶段包括:$match过滤文档、$group分组统计、$project重塑字段、$sort排序、$limit与$skip限制数量、$lookup关联其他集合、$unwind展开数组。每个阶段的输出作为下一阶段的输入,整体形成一个处理流水线。
// 统计各城市已支付订单的总金额与订单数,按金额降序取前三
db.orders.aggregate([
{ $match: { status: "paid" } }, // 过滤已支付订单
{ $group: {
_id: "$city", // 按城市分组
totalAmount: { $sum: "$amount" }, // 汇总金额
count: { $sum: 1 } // 统计条数
}},
{ $sort: { totalAmount: -1 } },
{ $limit: 3 }
])
// 使用 $lookup 关联用户集合,再展开用户信息
db.orders.aggregate([
{ $lookup: {
from: "users",
localField: "userId",
foreignField: "_id",
as: "userInfo"
}},
{ $unwind: "$userInfo" },
{ $project: { orderNo: 1, "userInfo.name": 1 } }
])管道阶段的顺序很关键。把$match放在最前面可以尽早减少参与后续计算的数据量,还能让查询命中索引;如果把$match放在$group之后,过滤就发生在内存中,性能差距可能非常大。同理,$limit和$skip应尽量放在$sort之后、其他重计算阶段之前。
另一个实用细节是$group的_id字段,它定义分组的维度,写null表示全表作为一组,多字段分组时写成对象形式,例如{_id: {city: "$city", type: "$type"}}。聚合表达式里的字段引用必须加$前缀,这是新手最容易遗漏的地方。
find与聚合管道的区别及选型建议
从结果形态看,find返回的是文档游标,结果永远是原集合文档的子集或投影;聚合管道返回的可以是全新结构的文档,分组统计、多集合拼接都不在话下。从能力上看,find只能做单表查询,而$lookup让聚合管道具备了类JOIN的能力。
从性能角度看,简单的条件查询find天然更快,解析开销小,索引利用直接。聚合管道虽然功能强,但每个阶段都有调度成本,如果只是过滤加投影,用$match加$project去模拟find属于杀鸡用牛刀。另外,聚合默认受16MB单文档限制和100MB内存限制约束,大数据量分组需要allowDiskUse: true允许落盘临时结果。
实际选型可以遵循一个简单原则:只需要查数据时用find,需要对数据做计算、变形、汇总时用aggregate。两者也不是互斥的,聚合管道的第一个$match阶段本质上就承担了find的角色,语法几乎一致。写查询时记得先用explain()查看执行计划,确认条件命中了索引,再考虑管道阶段的排列是否合理,这样无论用哪套命令都能拿到理想的响应速度。
MongoDB聚合管道find查询MongoDB命令修改时间:2026-09-04 01:01:02