Skip to content

查询与聚合

MongoDB 查询使用 BSON Filter 表达条件,Projection 控制返回字段,Update Operator 描述局部修改。复杂数据处理使用 Aggregation Pipeline,让文档依次通过多个 Stage。


查询组成

javascript
db.users.find(
  {
    enabled: true,
    age: { $gte: 18 },
    tags: "vip",
    "profile.city": { $in: ["Hefei", "Shanghai"] }
  },
  { username: 1, age: 1, "profile.city": 1 }
).sort({ createdAt: -1, _id: -1 }).limit(20)
部分作用SQL 类比
Filter匹配文档WHERE
Projection选择或排除字段SELECT column
Sort指定结果顺序ORDER BY
Limit / Skip限制和跳过结果LIMIT / OFFSET
Collation字符串比较和排序规则Collation

点路径可以访问嵌套 Field。查询数组中的多个条件是否要求同一个数组元素满足,需要区分普通点路径与 $elemMatch,否则语义可能扩大到不同元素分别满足。


局部更新

javascript
db.users.updateOne(
  { _id: userId, version: 3 },
  {
    $set: { "profile.city": "Hefei", updatedAt: new Date() },
    $inc: { balance: 10, version: 1 },
    $addToSet: { tags: "vip" }
  }
)
Operator作用
$set / $unset设置或移除字段
$inc / $mul原子数值增量或乘法
$push / $pull向数组追加或移除元素
$addToSet不重复地加入数组元素
$rename重命名 Field
Positional Operator更新匹配的数组元素

用整个新文档 replaceOne 会替换除 _id 外的文档内容;普通业务更新通常使用操作符,避免覆盖并发写入的其他字段。Filter 中加入 Version 可以实现乐观并发控制。


Aggregation Pipeline

javascript
db.orders.aggregate([
  { $match: { status: "paid", createdAt: { $gte: start } } },
  { $unwind: "$items" },
  {
    $group: {
      _id: "$items.productId",
      quantity: { $sum: "$items.quantity" },
      amount: { $sum: { $multiply: ["$items.price", "$items.quantity"] } }
    }
  },
  { $sort: { amount: -1 } },
  { $limit: 20 }
])
Stage作用
$match过滤文档,应尽量尽早缩小数据集
$project / $set选择、计算或增加 Field
$unwind把数组元素展开为多条 Pipeline Document
$group按键聚合,可能消耗大量内存
$sort排序;前置条件匹配时可能使用索引
$lookup与另一个 Collection 关联
$facet对同一输入并行执行多个子管道
$setWindowFields执行窗口计算
$merge / $out把结果写入 Collection

Pipeline 的 Stage 顺序会改变语义和成本。应尽早 $match、减少不必要字段和数组展开,并通过 explain 验证索引、扫描文档数、排序和执行时间。


$lookup 的边界

$lookup 让 MongoDB 能够做 Collection 间关联,但不能据此照搬高度规范化模型:

  • 关联字段需要合适索引。
  • 分片环境中的路由和数据分布会影响成本。
  • 多层 $lookup$unwind 可能放大中间结果。
  • 经常共同读取且生命周期一致的数据,嵌入通常更直接。

参考资料