首页 / MongoDB 入门教程 / $unwind 展开数组

MongoDB 入门教程

$unwind 展开数组

本教程共 50 篇 · 第 33 篇 · 更新于 2026-07-30 · 约 6 分钟阅读

MongoDBMongoDB 入门教程unwind展开数组数组拆行preserveNullAndEmptyArrays

33. $unwind 展开数组

本节目标:学会用 $unwind 把数组字段「炸开」成多行,让数组里的每个元素都成为一条独立文档,并知道何时用 preserveNullAndEmptyArrays 留住空数组文档。

很多统计要「按数组里的每个元素」来算,比如「每个商品卖了多少件」。可订单里的商品是 items 数组,直接 $group 没法逐行算。$unwind 就是把这个数组拆成多行的解法。

db.orders.insertMany([
  { _id: 1001, user_id: 1, items: [
    { product: "机械键盘", qty: 1, price: 399 },
    { product: "无线鼠标", qty: 2, price: 129 }
  ] },
  { _id: 1002, user_id: 2, items: [
    { product: "27寸显示器", qty: 1, price: 1099 }
  ] },
  { _id: 1003, user_id: 3, items: [] }
])

基本用法:数组变多行

$unwind: "$items" 会把每条订单,按 items 的元素数量「复制」成多条,每条里 items 不再是数组,而是单个对象:

db.orders.aggregate([
  { $unwind: "$items" }
])

_id:1001 拆成 2 条(键盘、鼠标各一条),_id:1002 拆成 1 条。原本的 user_id 等字段会原样保留在每条里。

Note

拆完后 items 字段成了普通对象,不是数组了。所以可以写 "$items.product""$items.qty" 直接访问子字段。

默认行为:空数组文档会被丢弃

注意上面的 _id:1003,它的 items 是空数组 []。默认情况下 $unwind 会把它整个丢掉,因为「没有元素可生成行」。

preserveNullAndEmptyArrays:保留空/缺失文档

preserveNullAndEmptyArrays: true,即使数组为空或字段缺失,原文档也保留下来(此时 items 为 null):

// 空数组的订单也保留,items 变为 null
db.orders.aggregate([
  { $unwind: { path: "$items", preserveNullAndEmptyArrays: true } }
])

这样 _id:1003 仍会出现在结果里,itemsnull

Tip

要不要保留空数组文档,看业务:统计「订单数」要保留;统计「商品销量」可丢弃(没有商品可算)。我的习惯是默认不带,需要保活时才加。

实战:拆行后按商品统计销量

配合 $group,就能算出每个商品总共卖了多少件:

db.orders.aggregate([
  { $unwind: "$items" },
  {
    $group: {
      _id: "$items.product",
      totalQty: { $sum: "$items.qty" }
    }
  }
])

结果形如 { _id: "机械键盘", totalQty: 1 }{ _id: "无线鼠标", totalQty: 2 }。这正是 $unwind 最常见的搭档用法。

$unwind 与 $lookup 常联用

上一章讲过,订单关联商品表时,先 $unwind: "$items" 把商品行拆开,再 $lookup 关联 products,才能逐行匹配。两者是「数组类统计」的标准组合。

选项效果
$unwind: "$字段"数组每个元素生成一行,空数组文档丢弃
preserveNullAndEmptyArrays: true空数组/缺失字段的文档也保留

下一章我们看聚合里那些「表达式」:日期、字符串、算术、条件判断,它们让计算更丰富。