首页/数据/NoSQL 速查/聚合 $unwind 展开数组
MongoDB99 条

聚合 $unwind 展开数组

$unwind 把数组字段拆成多条输出文档(每条对应一个元素),是数组聚合与 $group 组合的常见前置步骤。

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

$unwind 干什么

$unwind 把数组字段拆开:数组里有几个元素,就输出几条文档,其余字段逐条复制。它是「文档内数组」通往「按元素分组统计」的桥:不展开就没法按 items.sku 这种元素级字段做 $group 汇总。

基本信息

适用版本MongoDB 4.x-8.x / mongosh
简写语法{ $unwind: "$items" }
完整写法{ path, includeArrayIndex, preserveNullAndEmptyArrays }
阶段顺序通常紧跟 $match,放在 $group 之前
嵌套数组需要连续多次 $unwind

典型使用场景

  • 订单明细汇总:展开 items 后按 $items.sku 分组求销量与金额
  • 标签/属性统计:把 tags 数组展开,得到每个标签的使用次数
  • 明细与主表关联:展开后再 $lookup 补商品维度信息
  • 按元素排序取 TopN:展开后 $sort + $limit,得到最贵/最多的明细行
  • 去重与占比计算:展开数组后 $group 求 distinct 值数量

展开订单明细

展开订单明细
db.orders.aggregate([
  { $match: { ts: { $gte: ISODate("2026-10-01T00:00:00Z") } } },   # 先过滤,别等展开后再筛
  { $unwind: "$items" },                                            # 每个 items 元素输出一条文档
  { $group: { _id: "$items.sku", total: { $sum: "$items.qty" } } },
  { $sort: { total: -1 } },
  { $limit: 10 }
])

# 保留空数组/缺失字段的文档,否则这类订单会被整条丢掉
db.orders.aggregate([ { $unwind: { path: "$items", preserveNullAndEmptyArrays: true } } ])
# 把元素下标带出来,便于恢复原始顺序
db.orders.aggregate([ { $unwind: { path: "$items", includeArrayIndex: "idx" } } ])

选项与行为

选项作用注意点
path要展开的数组路径,必须带 $ 前缀写成 "items" 会直接报错
preserveNullAndEmptyArraystrue 时保留空数组与缺失字段的文档默认 false,会让这些文档整体消失
includeArrayIndex把元素下标写入新字段下标从 0 开始,配合 $sort 可还原原顺序
嵌套数组一次只展开一层内层数组要再写一个 $unwind 阶段
不带 preserveNullAndEmptyArrays 时,数组为空或字段缺失的文档会被整条丢弃:统计总数时结果会比实际少,排查时很容易误判为数据丢失。
对象数组用点号访问元素字段,如 $items.sku、$items.price;展开后原文档的其余字段全部复制,所以 $group 里要显式选择需要的字段,避免结果膨胀。
$unwind 会把文档数放大到元素总数,位置越靠前代价越大;把 $match 放在 $unwind 之前先收窄数据,是这类管道的常规优化手段。

易错点

  • 路径漏掉 $ 前缀,写 "items" 而不是 "$items",聚合直接报错中断
  • 空数组或字段缺失的文档被默认丢弃,统计口径悄悄变小 → 按需加 preserveNullAndEmptyArrays: true
  • 展开后文档数成倍放大,$group 阶段内存超过 100MB 报错 → 先 $match 收窄并考虑 allowDiskUse
  • 嵌套数组只展开了一层,内层仍是数组,分组结果把整串数组当成一个值
  • 把 $unwind 放在 $match 之后却不带 preserveNull,过滤条件写的是被展开后的字段时逻辑容易反直觉

数据来源与参考

  • MongoDB Manual: $unwind
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌