对于 AI 代理:可在 https://www.mongodb.com/zh-cn/docs/llms.txt 获取文档索引—通过在任何 URL 路径后添加 .md 可获取所有页面的 Markdown 版本。

$unwind(聚合阶段)

$unwind

解构输入文档中的数组字段,以便为每个元素输出文档。每个输出文档都是输入文档,并用该元素替换该数组字段的值。

可以使用 $unwind 查找托管在以下环境中的部署:

  • MongoDB Atlas:用于云中 MongoDB 部署的完全托管服务

传递字段路径(Field Path)操作数或文档操作数以展开数组字段。

您可以将数组字段路径(Field Path)传递给 $unwind。使用该语法时,如果字段值为 null、缺失或空数组,则 $unwind 不会输出文档。

{ $unwind: <field path> }

如需指定字段路径,在字段名称前加上美元符号 $,并用引号括起来。

您可以将文档传递给 $unwind 以指定选项。

{ $unwind: { path: <field path>, includeArrayIndex: <string>, preserveNullAndEmptyArrays: <boolean> }}
字段
类型
说明

字符串

数组字段的字段路径。如需指定字段路径,请在字段名称前加上美元符号 $,并用引号括起来。

字符串

可选。新字段的名称,用于保存该元素的数组索引。名称不能以美元符号 $ 开头。

布尔

可选。

  • 如果为 true,如果 path 缺失或是空数组,$unwind 将在输出文档中忽略输出字段。如果值为 null,则该字段仍为 null。

  • 如果为 false,如果 path 为 null、缺失或空大量,则 $unwind 不会输出文档。

默认值为 false。

当 path 的值未解析为数组时,$unwind 的行为如下:

  • 如果该值未缺失、不是 null 且不是空数组,则 $unwind 会按原样使用该值输出单个文档。

  • 如果指定了 includeArrayIndex,则数组输入的索引为 0,非数组输入的索引为 null。列表中靠后的文档的索引大于 0。

  • 如果该值缺失、为 null 或空数组,则 $unwind 遵循 keepNullAndEmptyArrays 选项。当指定 includeArrayIndex 并保留文档时,索引为 null。

如果为输入文档中不存在的字段指定路径,或者该字段为空数组,则默认情况下,$unwind 会忽略此输入文档,并且不会为该输入文档输出文档。

请使用 preserveNullAndEmptyArrays 选项输出数组字段缺失、为 null 或空数组的文档。

本页上的示例使用来自 sample_mflix 数据集的数据。有关如何将此数据集加载到您的自管理 MongoDB 部署中的详细信息,请参阅 加载示例数据集。如果您对示例数据库进行了任何修改,您可能需要删除并重新创建数据库,才能运行此页面上的示例。

以下聚合使用 $unwind 阶段为 Inception 电影文档的 genres 数组中的每个元素输出一个文档:

db.movies.aggregate( [ { $match: { title: "Inception" } }, { $project: { _id: 0, title: 1, genres: 1 } }, { $unwind: "$genres" }] )
[ { genres: 'Action', title: 'Inception' }, { genres: 'Mystery', title: 'Inception' }, { genres: 'Sci-Fi', title: 'Inception' }]

每个输出文档都与输入文档完全相同,只是 genres 字段的值不同,该字段现在包含原始 genres 数组中的单个元素。

以下聚合使用 $unwind 阶段处理四个电影文档。两个文档 ("La porta del cielo" 和 "Neecha Nagar") 没有 genres 字段:

db.movies.aggregate( [ { $match: { title: { $in: [ "Inception", "Brave", "La porta del cielo", "Neecha Nagar" ] } } }, { $project: { _id: 0, title: 1, genres: 1 } }, { $unwind: { path: "$genres" } }] )
[ { genres: 'Animation', title: 'Brave' }, { genres: 'Adventure', title: 'Brave' }, { genres: 'Comedy', title: 'Brave' }, { genres: 'Action', title: 'Inception' }, { genres: 'Mystery', title: 'Inception' }, { genres: 'Sci-Fi', title: 'Inception' }]
  • 在 "Brave" 和 "Inception" 文档中,genres 是一个填充数组。$unwind 为每个元素返回一个文档。

  • "La porta del cielo" 和 "Neecha Nagar" 文档中没有 genres 字段,因此 $unwind 不会为它们返回任何文档。

注意

{ path: <FIELD> } 语法是可选的。以下 $unwind 操作是等效的。

db.<COLLECTION>.aggregate( [ { $unwind: "<FIELD>" } ])
db.<COLLECTION>.aggregate( [ { $unwind: { path: "<FIELD>" } } ])

preserveNullAndEmptyArrays 和 includeArrayIndex 示例使用来自 sample_mflix.movies 集合的文档。

以下 $unwind 操作使用 preserveNullAndEmptyArrays 选项来纳入 genres 字段缺失的文档。

db.movies.aggregate( [ { $match: { title: { $in: [ "Inception", "Brave", "La porta del cielo", "Neecha Nagar" ] } } }, { $project: { _id: 0, title: 1, genres: 1 } }, { $unwind: { path: "$genres", preserveNullAndEmptyArrays: true } }] )
[ { title: 'La porta del cielo' }, { title: 'Neecha Nagar' }, { genres: 'Animation', title: 'Brave' }, { genres: 'Adventure', title: 'Brave' }, { genres: 'Comedy', title: 'Brave' }, { genres: 'Action', title: 'Inception' }, { genres: 'Mystery', title: 'Inception' }, { genres: 'Sci-Fi', title: 'Inception' }]

以下$unwind 操作使用 includeArrayIndex 选项以在输出中纳入数组索引。

db.movies.aggregate( [ { $match: { title: "Inception" } }, { $project: { _id: 0, title: 1, genres: 1 } }, { $unwind: { path: "$genres", includeArrayIndex: "genreIndex" } }] )
[ { genres: 'Action', title: 'Inception', genreIndex: Long('0') }, { genres: 'Mystery', title: 'Inception', genreIndex: Long('1') }, { genres: 'Sci-Fi', title: 'Inception', genreIndex: Long('2') }]

以下管道将 genres 数组展开,并按类型对生成的文档进行分组,以统计每种类型的电影数量:

db.movies.aggregate( [ // First Stage { $match: { title: { $in: [ "The Dark Knight", "Inception", "Interstellar", "Brave" ] } } }, // Second Stage { $project: { _id: 0, title: 1, genres: 1 } }, // Third Stage { $unwind: "$genres" }, // Fourth Stage { $group: { _id: "$genres", movieCount: { $sum: 1 } } }, // Fifth Stage { $sort: { movieCount: -1 } }] )
[ { _id: 'Adventure', movieCount: 2 }, { _id: 'Action', movieCount: 2 }, { _id: 'Drama', movieCount: 2 }, { _id: 'Sci-Fi', movieCount: 2 }, { _id: 'Crime', movieCount: 1 }, { _id: 'Animation', movieCount: 1 }, { _id: 'Comedy', movieCount: 1 }, { _id: 'Mystery', movieCount: 1 }]

您可以在单个管道中多次应用 $unwind,以展开包含多个数组字段的文档。以下操作先展开 genres 数组,然后展开 cast 数组,为每个流派-演员组合生成一个扁平文档,然后按流派分组以计算每个流派中的总演员出场次数:

db.movies.aggregate( [ // First Stage { $match: { title: { $in: [ "Inception", "The Dark Knight", "Interstellar" ] } } }, // Second Stage { $project: { _id: 0, title: 1, genres: 1, cast: 1 } }, // Third Stage { $unwind: "$genres" }, // Fourth Stage { $unwind: "$cast" }, // Fifth Stage { $group: { _id: "$genres", castAppearances: { $sum: 1 } } }] )
[ { _id: 'Adventure', castAppearances: 4 }, { _id: 'Crime', castAppearances: 4 }, { _id: 'Action', castAppearances: 8 }, { _id: 'Drama', castAppearances: 8 }, { _id: 'Mystery', castAppearances: 4 }, { _id: 'Sci-Fi', castAppearances: 8 }]

有关相关阶段和表达式,请参阅 $group、$sum、$sort 和 $multiply。

有关完整示例,请参阅展开数组和分组数据教程。