定义
兼容性
可以使用 $unwind 查找托管在以下环境中的部署:
- MongoDB Atlas:用于云中 MongoDB 部署的完全托管服务
MongoDB Enterprise:基于订阅、自我管理的 MongoDB 版本
MongoDB Community:源代码可用、免费使用且可自行管理的 MongoDB 版本
语法
传递字段路径(Field Path)操作数或文档操作数以展开大量字段。
字段路径操作数
您可以将大量字段路径(Field Path)传递给 $unwind。使用此语法,如果字段值为 null、缺失或空大量,则 $unwind 不会输出文档。
{ $unwind: <field path> }
如需指定字段路径,在字段名称前加上美元符号 $,并用引号括起来。
带选项的文档操作数
您可以将文档传递给 $unwind 来指定选项。
{ $unwind: { path: <field path>, includeArrayIndex: <string>, preserveNullAndEmptyArrays: <boolean> } }
字段 | 类型 | 说明 |
|---|---|---|
字符串 | 数组字段的字段路径。如需指定字段路径,请在字段名称前加上美元符号 | |
字符串 | 可选。新字段的名称,用于保存该元素的数组索引。名称不能以美元符号 | |
布尔 | 可选。
默认值为 |
行为
非数组字段路径
当 path 的值未解析为数组时,$unwind 的行为如下:
如果该值未缺失、不是
null且不是空数组,则$unwind会按原样使用该值输出单个文档。如果指定了
includeArrayIndex,则数组输入的索引为0,非数组输入的索引为null。列表中靠后的文档的索引大于0。如果该值缺失、为
null或空大量,则$unwind遵循 keepNullAndEmptyArrays 选项。当指定includeArrayIndex并保留文档时,索引为null。
缺失字段
如果为输入文档中不存在的字段指定路径,或者该字段为空大量,则默认,$unwind 会忽略输入文档,并且不会输出该输入文档的文档。
要输出大量字段缺失、为 null 或空大量的文档,请使用preserveNullAndEmptyArrays 选项。
示例
本页上的示例使用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>" } } ] )
keepNullAndEmptyArrays 和 includeArrayIndex
keepNullAndEmptyArrays 和 includeArrayIndex 示例使用 sample_mflix.movies集合中的文档。
preserveNullAndEmptyArrays
以下 $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' } ]
includeArrayIndex
以下 $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 } ]
本页上的C#示例使用Atlas示例数据集中的 sample_mflix数据库。要学习;了解如何创建免费的MongoDB Atlas 群集并加载示例数据集,请参阅MongoDB .NET/ C#驱动程序文档中的入门。
以下 Movie 类对 sample_mflix.movies 集合中的文档进行建模:
public class Movie { public ObjectId Id { get; set; } public int Runtime { get; set; } public string Title { get; set; } public string Rated { get; set; } public List<string> Genres { get; set; } public string Plot { get; set; } public ImdbData Imdb { get; set; } public int Year { get; set; } public int Index { get; set; } public string[] Comments { get; set; } [] public DateTime LastUpdated { get; set; } }
注意
用于 Pascal Case 的 ConventionPack
此页面上的 C# 类在其属性名称中使用 Pascal 命名法,而 MongoDB 集合中的字段名称则使用 camel 命名法。为了解决这种差异,可以在应用程序启动时使用以下代码注册一个 ConventionPack:
var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() }; ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true);
要使用MongoDB .NET/ C#驾驶员将$unwind PipelineDefinition阶段添加到聚合管道,请对 对象调用 Unwind() 方法。
以下示例创建了一个管道阶段,用于遍历每个输入 Movie文档中的 Genres字段。对于 Genres字段中的每个值,该阶段都会创建新的 Movie文档,并使用输入文档中的 Genres 值填充其 Genres字段。
var pipeline = new EmptyPipelineDefinition<Movie>() .Unwind(m => m.Genres);
您可以使用 AggregateUnwindOptions对象自定义 Unwind() 方法的行为。
以下示例执行与上一示例相同的操作,但还包括以下选项:
PreserveNullAndEmptyArrays确保输出中包含Genres字段中包含空大量的文档。IncludeArrayIndex选项将名为Index的新字段添加到每个输出文档中。该字段的值是输入文档的Genres大量中Genres字段值的大量索引。
var pipeline = new EmptyPipelineDefinition<Movie>() .Unwind(m => m.Genres, new AggregateUnwindOptions<Movie>() { PreserveNullAndEmptyArrays = true, IncludeArrayIndex = new ExpressionFieldDefinition<Movie, int>( m => m.Index) });
本页上的 Node.js 示例使用 Atlas 示例数据集中的 sample_mflix数据库。要学习如何创建免费的MongoDB Atlas 集群并加载示例数据集,请参阅MongoDB Node.js驱动程序文档中的入门。
要使用MongoDB Node.js驱动程序将 $unwind 阶段添加到聚合管道,请在管道对象中使用 $unwind操作符。
以下示例创建了一个管道阶段,用于遍历每个输入 movie文档中的 genres字段。对于 genres字段中的每个值,该阶段都会创建新的 movie文档,并使用输入文档中的 genres 值填充其 genres字段。然后,该示例运行聚合管道:
const pipeline = [{ $unwind: "$genres" }]; const cursor = collection.aggregate(pipeline); return cursor;
您可以自定义 $unwind 方法的行为。以下示例执行与上一示例相同的操作,但还包括以下选项:
preserveNullAndEmptyArrays确保输出中包含genres字段中包含空大量的文档。includeArrayIndex向每个输出文档添加一个名为index的新字段。该字段包含输入文档的genres字段中genres值的大量索引。
const pipeline = [ { $unwind: { path: "$genres", preserveNullAndEmptyArrays: true, includeArrayIndex: "index" } } ]; const cursor = collection.aggregate(pipeline); return cursor;
了解详情
有关相关阶段和表达式,请参阅 $group、$sum、$sort 和 $multiply。