MongoDB聚合:$unwind

2024-02-12 21:12
文章标签 mongodb 聚合 unwind

本文主要是介绍MongoDB聚合:$unwind,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

使用$unwind可以对输入文档数组字段进行结构,为每个数组元素输出一个文档,并且每个输出文档都是输入文档数组字段的值。相当于将内嵌的数组文档提升到了顶层。

语法

可以通过字段路径或文档操作符来展开数组字段。

通过字段操作符展开

可以将数组字段路径传递给$unwind,如果字段值为null、不存在或者是个空数组,则$unwind不会输出文档。

指定的字段路径时,字段名前面必须使用$前缀,并用引号引起来。

{ $unwind: <field path> }

使用文档操作符选项

可以通过给$unwind传递一个文档来指定展开时的行为:

{$unwind:{path: <field path>,includeArrayIndex: <string>,preserveNullAndEmptyArrays: <boolean>}
}

|字段|类型|说明|
|path|string|数组字段的路径,字段名前面必须使用$前缀,并用引号引起来|
|includeArrayIndex|string|可选,给数组元素位置字段指定字段名,不能以$开始|
|preserveNullAndEmptyArrays|boolean|可选,缺省值为false。如果为true,当path为空、不存在或数组元素为空,$unwind输出文档,否则如果为false则不输出文档|

使用

非数组字段路径

  • 当操作符没有解析为数组,但不是缺失、空或空数组时,$unwind会将操作符视为单元素数组。

  • 当操作符为空、缺失或空数组时,$unwind会按照preserveNullAndEmptyArrays选项执行。

字段缺失

如果输入文档中不存在指定字段的路径或字段是个空数组,默认情况下$unwind会忽略输入文档且不输出文档。可以使用preserveNullAndEmptyArrays选项来强制输出文档。

举例

展开数组

inventory文档添加一个文档:

db.inventory.insertOne({ "_id" : 1, "item" : "ABC1", sizes: [ "S", "M", "L"] })

下面的聚合使用$unwind阶段为sizes数组的每个元素输出一个文档:

db.inventory.aggregate( [ { $unwind : "$sizes" } ] )

操作返回:

{ "_id" : 1, "item" : "ABC1", "sizes" : "S" }
{ "_id" : 1, "item" : "ABC1", "sizes" : "M" }
{ "_id" : 1, "item" : "ABC1", "sizes" : "L" }

每个文档都与输入文档完全相同,只是sizes字段的值不同,该字段的值来自原始sizes数组。

缺失或数组为空

准备clothing集合数据:

db.clothing.insertMany([{ "_id" : 1, "item" : "Shirt", "sizes": [ "S", "M", "L"] },{ "_id" : 2, "item" : "Shorts", "sizes" : [ ] },{ "_id" : 3, "item" : "Hat", "sizes": "M" },{ "_id" : 4, "item" : "Gloves" },{ "_id" : 5, "item" : "Scarf", "sizes" : null }
])

下列情况下,$unwindsizes字段看做一个文档:

  • 字段存在
  • 字段的值不为空
  • 字段的值不是空数组

使用$unwind展开sizes数组:

db.clothing.aggregate( [ { $unwind: { path: "$sizes" } } ] )

操作返回:

{ _id: 1, item: 'Shirt', sizes: 'S' },
{ _id: 1, item: 'Shirt', sizes: 'M' },
{ _id: 1, item: 'Shirt', sizes: 'L' },
{ _id: 3, item: 'Hat', sizes: 'M' }
  • _id: 1的文档中,sizes是一个有元素的数组,$unwindsizes字段的每个元素生成了一个文档
  • _id: 3的文档中,sizes被解析为只有一个元素的数组
  • _id: 2_id: 4_id: 5文档则没有返回,因为sizes字段不能被解析为单元素数组。

注意:{path: <FIELD>}是可选的,下面的两个$unwind操作是等价的:

db.clothing.aggregate( [ { $unwind: "$sizes" } ] )
db.clothing.aggregate( [ { $unwind: { path: "$sizes" } } ] )

preserveNullAndEmptyArrays 和 includeArrayIndex

创建inventory2并插入下面数据:

db.inventory2.insertMany([{ "_id" : 1, "item" : "ABC", price: NumberDecimal("80"), "sizes": [ "S", "M", "L"] },{ "_id" : 2, "item" : "EFG", price: NumberDecimal("120"), "sizes" : [ ] },{ "_id" : 3, "item" : "IJK", price: NumberDecimal("160"), "sizes": "M" },{ "_id" : 4, "item" : "LMN" , price: NumberDecimal("10") },{ "_id" : 5, "item" : "XYZ", price: NumberDecimal("5.75"), "sizes" : null }
])
preserveNullAndEmptyArrays

下面的$unwind操作使用preserveNullAndEmptyArrays选项,当sizes字段为null、缺失或空数组时,仍然输出文档。

db.inventory2.aggregate( [{ $unwind: { path: "$sizes", preserveNullAndEmptyArrays: true } }
] )

输出包含了sizesnull、缺失或为空数组时的文档:

{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "S" }
{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "M" }
{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "L" }
{ "_id" : 2, "item" : "EFG", "price" : NumberDecimal("120") }
{ "_id" : 3, "item" : "IJK", "price" : NumberDecimal("160"), "sizes" : "M" }
{ "_id" : 4, "item" : "LMN", "price" : NumberDecimal("10") }
{ "_id" : 5, "item" : "XYZ", "price" : NumberDecimal("5.75"), "sizes" : null }
includeArrayIndex

下面的$unwind操作使用includeArrayIndex选项,在输出文档中添加了数组元素索引字段。

db.inventory2.aggregate( [{$unwind:{path: "$sizes",includeArrayIndex: "arrayIndex"}}])

操作展开了sizes数组,并为输出文档增加了一个数组元素索引字段arrayIndex,如果sizes字段不能被解析为一个有元素的数组,但又不是缺失、为空或空数组,则arrayIndex字段为空。

{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "S", "arrayIndex" : NumberLong(0) }
{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "M", "arrayIndex" : NumberLong(1) }
{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "L", "arrayIndex" : NumberLong(2) }
{ "_id" : 3, "item" : "IJK", "price" : NumberDecimal("160"), "sizes" : "M", "arrayIndex" : null }

对展开的数组做分组汇总

创建并填充inventory2集合:

db.inventory2.insertMany([{ "_id" : 1, "item" : "ABC", price: NumberDecimal("80"), "sizes": [ "S", "M", "L"] },{ "_id" : 2, "item" : "EFG", price: NumberDecimal("120"), "sizes" : [ ] },{ "_id" : 3, "item" : "IJK", price: NumberDecimal("160"), "sizes": "M" },{ "_id" : 4, "item" : "LMN" , price: NumberDecimal("10") },{ "_id" : 5, "item" : "XYZ", price: NumberDecimal("5.75"), "sizes" : null }
])

下面的操作展开sizes数组,并对展开文档的size字段进行分组:

db.inventory2.aggregate( [//阶段1{$unwind: { path: "$sizes", preserveNullAndEmptyArrays: true }},//阶段2{$group:{_id: "$sizes",averagePrice: { $avg: "$price" }}},//阶段3{$sort: { "averagePrice": -1 }}
] )
阶段1

$unwind阶段为sizes数组的每个元素输出一个文档,该阶段使用preserveNullAndEmptyArrays选项为sizes字段为空、缺失或空数组的情况都输出了文档,该阶段完成后输出下面的文档进入下一阶段:

{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "S" }
{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "M" }
{ "_id" : 1, "item" : "ABC", "price" : NumberDecimal("80"), "sizes" : "L" }
{ "_id" : 2, "item" : "EFG", "price" : NumberDecimal("120") }
{ "_id" : 3, "item" : "IJK", "price" : NumberDecimal("160"), "sizes" : "M" }
{ "_id" : 4, "item" : "LMN", "price" : NumberDecimal("10") }
{ "_id" : 5, "item" : "XYZ", "price" : NumberDecimal("5.75"), "sizes" : null }
阶段2

$group阶段根据sizes进行分组,并计算所有尺寸价格的平均值。该阶段完成后,生成下面的文档进入下一阶段:

{ "_id" : "S", "averagePrice" : NumberDecimal("80") }
{ "_id" : "L", "averagePrice" : NumberDecimal("80") }
{ "_id" : "M", "averagePrice" : NumberDecimal("120") }
{ "_id" : null, "averagePrice" : NumberDecimal("45.25") }
阶段3

$sort阶段根据averagePrice字段值从大到小对文档进行排序,该阶段完成后返回下面的文档:

{ "_id" : "M", "averagePrice" : NumberDecimal("120") }
{ "_id" : "L", "averagePrice" : NumberDecimal("80") }
{ "_id" : "S", "averagePrice" : NumberDecimal("80") }
{ "_id" : null, "averagePrice" : NumberDecimal("45.25") }

这篇关于MongoDB聚合:$unwind的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/703622

相关文章

Go Mongox轻松实现MongoDB的时间字段自动填充

《GoMongox轻松实现MongoDB的时间字段自动填充》这篇文章主要为大家详细介绍了Go语言如何使用mongox库,在插入和更新数据时自动填充时间字段,从而提升开发效率并减少重复代码,需要的可以... 目录前言时间字段填充规则Mongox 的安装使用 Mongox 进行插入操作使用 Mongox 进行更

使用Python实现操作mongodb详解

《使用Python实现操作mongodb详解》这篇文章主要为大家详细介绍了使用Python实现操作mongodb的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、示例二、常用指令三、遇到的问题一、示例from pymongo import MongoClientf

使用MongoDB进行数据存储的操作流程

《使用MongoDB进行数据存储的操作流程》在现代应用开发中,数据存储是一个至关重要的部分,随着数据量的增大和复杂性的增加,传统的关系型数据库有时难以应对高并发和大数据量的处理需求,MongoDB作为... 目录什么是MongoDB?MongoDB的优势使用MongoDB进行数据存储1. 安装MongoDB

Jenkins构建Maven聚合工程,指定构建子模块

一、设置单独编译构建子模块 配置: 1、Root POM指向父pom.xml 2、Goals and options指定构建模块的参数: mvn -pl project1/project1-son -am clean package 单独构建project1-son项目以及它所依赖的其它项目。 说明: mvn clean package -pl 父级模块名/子模块名 -am参数

ElasticSearch的DSL查询⑤(ES数据聚合、DSL语法数据聚合、RestClient数据聚合)

目录 一、数据聚合 1.1 DSL实现聚合 1.1.1 Bucket聚合  1.1.2 带条件聚合 1.1.3 Metric聚合 1.1.4 总结 2.1 RestClient实现聚合 2.1.1 Bucket聚合 2.1.2 带条件聚合 2.2.3 Metric聚合 一、数据聚合 聚合(aggregations)可以让我们极其方便的实现对数据的统计、分析、运算。例如:

七、Maven继承和聚合关系、及Maven的仓库及查找顺序

1.继承   2.聚合   3.Maven的仓库及查找顺序

生产mongodb 分片与集群 方案

链接:http://my.oschina.net/pwd/blog/411439#navbar-header 注:主要是有一键安装的脚本可以借鉴

mongodb基本命令和Java操作API示例

1.Mongo3.2 java API示例:http://www.cnblogs.com/zhangchaoyang/articles/5146508.html 2.MongoDB基本命:http://www.cnblogs.com/xusir/archive/2012/12/24/2830957.html 3.java MongoDB查询(一)简单查询: http://www.cnblogs

使用jetty和mongodb做个简易文件系统

使用jetty和mongodb做个简易文件系统 - ciaos 时间 2014-03-09 21:21:00   博客园-所有随笔区 原文   http://www.cnblogs.com/ciaos/p/3590662.html 主题  MongoDB  Jetty  文件系统 依赖库: 1,jetty(提供http方式接口) 2,mongodb的java驱动(访问mo

mongodb简单入门

一篇较好的mongodb常用操作命令:http://www.cnblogs.com/hoojo/archive/2011/06/01/2066426.html mongodb的java操作:http://www.cnblogs.com/cyhe/p/5451421.html