谈MongoDB伟大的聚合管道(Aggregation Pipeline)

本文涉及的产品
云数据库 MongoDB,独享型 2核8GB
推荐场景:
构建全方位客户视图
简介:

MongoDB聚合管道

使用聚合管道可以对集合中的文档进行变换和组合。 管道是由一个个功能节点组成的,这些节点用管道操作符来进行表示。聚合管道以一个集合中的所有文档作为开始,然后这些文档从一个操作节点流向下一个节点 ,每个操作节点对文档做相应的操作。这些操作可能会创建新的文档或者过滤掉一些不符合条件的文档,在管道中可以对文档进行重复操作。 管道表达式只可以操作当前管道中的文档,不能访问其他的文档:表达式操作可以在内存中完成对文档的转换。

语法格式:

 

db.runCommand({

    aggregate: "<collection>",

    pipeline: [ <stage>, <...> ],

    explain: <boolean>,

    allowDiskUse: <boolean>,

    cursor: <document>,

    bypassDocumentValidation: <boolean>

    })

//
					

    db.collection.aggregate([ <pipeline>, <...> ], options)

参数说明:

操作符

描述

aggregate

要聚合的集合名称

pipeline

管道操作符

explain

返回指定aggregate各个阶段管道的执行计划信息

allowDiskUse

每个阶段管道限制为100MB的内存,如果大于100MB的数据可以先写入临时文件。设置为true时,aggregate操作可时可以先将数据写入对应数据目录的子目录中 的唯一并以_tmp结尾的文档中。

cursor

指定游标的初始批批大小。光标的字段的值是一个与场batchSize文件。 }

bypassDocumentValidation

只有当你指定了$out操作符,使db.collection.aggregate绕过文档验证操作过程中。这让您插入不符合验证要求的文档。

管道操作符:

管道操作符

描述

$project

数据投影,主要用于重命名、增加和删除字段

$match

过滤操作,筛选符合条件文档,作为下一阶段的输入 $match的语法和查询表达式db.collection.find() 的语法相同 注意:1. 不能在$match操作符中使用$where 表达式操作符。 2. $match尽量出现在管道的前面,这样可以提早过滤文档,加快聚合速度。 3. 如果$match出现在最前面的话,可以使用索引来加快查询。

$limit

限制经过管道的文档数量 $limit的参数只能是一个正整数

$skip

从待操作集合开始的位置跳过文档的数目 $skip参数也只能为一个正整数

$unwind

将数组分解为单个的元素,并与文档的其余部分一同返回 注意:1.如果$unwind目标字段不存在,则整个文档都会被忽略过滤掉 2.如果$unwind目标字段不是一个数组,则会报错 3.如果$unwind目标字段数组为空,则该文档也会被忽略过滤掉

$group

可以将文档依据指定字段的不同值进行分组,如果选定了需要进行分组的字段,就可以将指定的字段传递给$group函数的_id字段注意:1.$group的输出是无序的。 2.$group操作默认实在内存中进行的,超过此限制会报错,若要允许处理大型数据集,allowDiskUse 将选项设置为启用 $group 操作真实写入临时文件。具体请参考官方文档

$sort

对文档按照指定字段排序 注意:1.如果将$sort放到管道前面的话可以利用索引,提高效率 2.在管道中如果$sort出现在$limit之前的话,$sort只会对前$limit个文档进行操作,这样在内存中也只会保留前$limit个文档,从而可以极大的节省内存 3.$sort操作符默认在内存中进行,,超过此限制会报错,若要允许处理大型数据集,allowDiskUse 将选项设置为启用 $group 操作真实写入临时文件。具体请参考官方文档

$geoNear

会返回一些坐标值,这些值以按照距离指定点距离由近到远进行排序

$sample

从待操作的集合中随机返回指定数量的文档 注意:如果指定的数量 N 大于等于集合文档总数的5%$sample 执行集合扫描,执行排序,然后选择前 N 的文档(受排序的内存限制如果 N 是小于 5%的集合中的文档总数 如果使用 WiredTiger 存储引擎,$sample 使用伪随机游标在抽样 N 文档集合。 如果使用 MMAPv1 存储引擎,$sample 使用 _id 索引随机选择 N 个文档。

$lookup

用于与统一数据库中其他集合之间进行join操作

$out

用户将聚合的结果输出到指定的集合,如果要使用$out则必须在整个管道操作的最后阶段 如果指定的集合尚不存在,$out 操作会在当前数据库中创建一个新的集合。集合不是可见的直到聚合完成。如果聚合失败,MongoDB 不会创建集合。 如果集合指定的 $out 操作已经存在,然后完成后的聚合,$out 阶段以原子方式以新的结果集合替换现有集合的,$out 操作不会更改任何存在于以前的集合的索引。如果聚合失败$out 则不会对现有集合做任何更改。

$redact

字段所处的document结构的级别. $redact还有三个重要的参数: 1$$DESCEND 返回包含当前document级别的所有字段,并且会继续判字段包含内嵌文档,内嵌文档的字段也会去判断是否符合条件。 2$$PRUNE:返回不包含当前文档或者内嵌文档级别的所有字段,不会继续检测此级别的其他字段,即使这些字段的内嵌文档持有相同的访问级别。 3$$KEEP:返回包含当前文档或内嵌文档级别的所有字段,不再继续检测此级别的其他字段,即使这些字段的内嵌文档中持有不同的访问级别。

聚合管道操作实例

提取字段

    db.order.aggregate({ $project: { cust_id: 1, price: 1 } });

db.order.aggregate({ $project: { items: 1, items: { sku: 1 } } });

重命名字段

db.order.aggregate({ $project: { "orderid": '$_id', _id: 0, "custid": '$cust_id' } });

db.order.aggregate({ $project: { items: { '_sku': '$sku', sku: 1 } } })

新建文档

db.order.aggregate({

    $project: {

        price: 1,

        details: { price: '$items.price' }

    }

});

注意:由于对字段进行重命名时,MongoDB并不会记录字段的历史名称,所以如果针对原来的字段创建过索引,那么聚合管道在进行排序时无法在下面的排序操作时使用索引, 应当尽量在修改字段名称之前使用排序

    db.order.aggregate([{ $project: { "orderid": '$_id', _id: 0, "custid": '$cust_id' } }, { $sort: { custid: -1 } }])

//建议写法
					

db.order.aggregate([{ $sort: { cust_id: -1 } }, { $project: { "orderid": '$_id', _id: 0, "custid": '$cust_id' } }])

{ $add: [ <expression1>, <expression2>, ... ] } 将多个数字或日期进行相加,只支持数字和时间格式,如果其中一个参数是日期,$add会将其他参数视为要添加到日期的毫秒

db.order.aggregate({

    $project: {

        "add": {

            "$add": ["$price", 1]

        }

    }

})

{ $subtract: [ <expression1>, <expression2> ] } 接受两个表达式作为参数,使用第一个表达式减去第二个表达式作为结果

db.order.aggregate({

    $project: {

        "subtract": {

            "$subtract": [{ "$add": ["$price", 12] }, 10]

        }

    }

})

{ $multiply: [ <expression1>, <expression2>, ... ] } 接受一个或多个表达式,并将它们相乘

db.order.aggregate({

    $project: {

        "multiply": { "$multiply": ["$price", 3] }

    }

})

{ $divide: [ <expression1>, <expression2> ] } 接受两个表达式作为参数,使用第一个表达式除以第二个表达式的商作为结果

db.order.aggregate({

    $project: {

        "divide": { "$divide": ["$price", 3] }

    }

})

更多数学表达式参考官方文档 https://docs.mongodb.com/manual/reference/operator/aggregation-arithmetic/

{ $cond: { if: <boolean-expression>, then: <true-case>, else: <false-case-> } } { $cond: [ <boolean-expression>, <true-case>, <false-case> ] }如果boolean-expressiontrue则执行true-case否则执行false-case

 

db.order.aggregate({

    $project: {

        "price": {

            "$cond": { if: { $gt: ["$price", 25] }, then: true, else: false }

        }

    }

});

//
					

db.order.aggregate({

    $project: {

        "price": {

            "$cond": [{ $gt: ["$price", 25] }, true, false]

        }

    }

});

{ $ifNull: [ , ] } 如果expression  null 则返回replacement-expression-if-null 否则返回expression的值

 

db.order.aggregate({

    $project: {

        "total": {

            "$ifNull": ["$total", 0]

        }

    }

})

{ $and: [ <expression1>, <expression2>, ... ] } 如果所有表达式都返回true,则结果为true,否则为false 除了布尔类型false,以下几种类型也为false,如:null,0,undefined ;其它值则为true,包括非0的值及数组

    //Example                             Result

{ $and: [1, "green"] }              true

{ $and: [] }                        true

{ $and: [[null], [false], [0]] }    true

{ $and: [null, true] }              false

{ $and: [0, true] }                 false

{ $or: [ <expression1>, <expression2>, ... ] } 只要有任意表达式为true,则结果为true,否则为false 除了布尔类型false,以下几种类型也为false,如:null,0,undefined ;其它值则为true,包括非0的值及数组

 

//Example                            Result

{ $or: [ true, false ] }            true

{ $or: [ [ false ], false ] }       true

{ $or: [ null, 0, undefined ] }       false

{ $or: [] }                        false

{ $not: [ <expression> ] } expression取反 除了布尔类型false,以下几种类型也为false,如:null,0,undefined ;其它值则为true,包括非0的值及数组

//total不存在为false,取反结果则为true

db.order.aggregate({

    $project: {

        not: {

            $not: "$total"

        }

    }

})

$match 过滤操作,筛选符合条件文档,作为下一阶段的输入 $match的语法和查询表达式db.collection.find() 的语法相同

    db.order.aggregate([{ $match: { cust_id: "1" } }, {

    $project: {

        "total": {

            "$ifNull": ["$total", 0]

        }

    }

}])

$out 用户将聚合的结果输出到指定的集合

db.order.aggregate([{ $match: { cust_id: "1" } }, {

    $project: {

        "total": {

            "$ifNull": ["$total", 0]

        }

    }

},

{ $out: "testaggregate" }])

$unwind 将数组分解为单个的元素,并与文档的其余部分一同返回

        db.order.aggregate({$unwind:"$items"})

$group 对数据进行分组 $group的时候必须要指定一个_id域,同时也可以包含一些算术类型的表达式操作符

    db.order.aggregate([

   {

       $unwind: "$items"

   },

   {

       $group: {

           _id: "$cust_id",

           qty: {

               $sum: "$items.qty"

           }

       }

   }

])

关系型数据库与MongoDB关于聚合的一些对比

关系型数据库

Mongodb

WHERE

$match

GROUP BY

$group

HAVING

$match

SELECT

$project

ORDER BY

$sort

LIMIT

$limit

SUM()

$sum

COUNT()

$sum

join

$lookup


相关实践学习
MongoDB数据库入门
MongoDB数据库入门实验。
快速掌握 MongoDB 数据库
本课程主要讲解MongoDB数据库的基本知识,包括MongoDB数据库的安装、配置、服务的启动、数据的CRUD操作函数使用、MongoDB索引的使用(唯一索引、地理索引、过期索引、全文索引等)、MapReduce操作实现、用户管理、Java对MongoDB的操作支持(基于2.x驱动与3.x驱动的完全讲解)。 通过学习此课程,读者将具备MongoDB数据库的开发能力,并且能够使用MongoDB进行项目开发。 &nbsp; 相关的阿里云产品:云数据库 MongoDB版 云数据库MongoDB版支持ReplicaSet和Sharding两种部署架构,具备安全审计,时间点备份等多项企业能力。在互联网、物联网、游戏、金融等领域被广泛采用。 云数据库MongoDB版(ApsaraDB for MongoDB)完全兼容MongoDB协议,基于飞天分布式系统和高可靠存储引擎,提供多节点高可用架构、弹性扩容、容灾、备份回滚、性能优化等解决方案。 产品详情: https://www.aliyun.com/product/mongodb
目录
相关文章
|
1月前
|
SQL NoSQL Unix
MongoDB 聚合
10月更文挑战第17天
25 4
|
2月前
|
SQL NoSQL Unix
MongoDB聚合操作总结
这篇文章总结了MongoDB中聚合操作的作用、方法、常见聚合表达式以及聚合管道的概念和常用操作符,以及SQL与MongoDB聚合操作的对应关系。
42 2
MongoDB聚合操作总结
|
1月前
|
SQL NoSQL 数据处理
深入探索MongoDB的聚合操作
【10月更文挑战第13天】
15 0
|
2月前
|
NoSQL MongoDB 数据库
python3操作MongoDB的crud以及聚合案例,代码可直接运行(python经典编程案例)
这篇文章提供了使用Python操作MongoDB数据库进行CRUD(创建、读取、更新、删除)操作的详细代码示例,以及如何执行聚合查询的案例。
33 6
|
2月前
|
SQL NoSQL JavaScript
04 MongoDB各种查询操作 以及聚合操作总结
文章全面总结了MongoDB中的查询操作及聚合操作,包括基本查询、条件筛选、排序以及聚合管道的使用方法和实例。
87 0
|
3月前
|
持续交付 jenkins Devops
WPF与DevOps的完美邂逅:从Jenkins配置到自动化部署,全流程解析持续集成与持续交付的最佳实践
【8月更文挑战第31天】WPF与DevOps的结合开启了软件生命周期管理的新篇章。通过Jenkins等CI/CD工具,实现从代码提交到自动构建、测试及部署的全流程自动化。本文详细介绍了如何配置Jenkins来管理WPF项目的构建任务,确保每次代码提交都能触发自动化流程,提升开发效率和代码质量。这一方法不仅简化了开发流程,还加强了团队协作,是WPF开发者拥抱DevOps文化的理想指南。
88 1
|
3月前
|
NoSQL BI 数据处理
【超实用攻略】MongoDB 聚合框架:从入门到精通,带你解锁数据处理新姿势!
【8月更文挑战第24天】MongoDB是一款以其灵活性和高性能闻名的NoSQL数据库。其强大的聚合框架采用管道式处理,允许用户定义多个数据处理阶段如过滤、分组等。本文通过示例数据库`orders`和`products`,演示如何利用聚合框架计算各产品的总销售额。示例代码展示了使用`$lookup`连接两集合、`$unwind`打平数组及`$group`按产品ID分组并计算总销售额的过程。这突显了聚合框架处理复杂查询的强大能力,是进行数据分析和报表生成的理想选择。
54 3
|
3月前
|
存储 NoSQL JavaScript
MongoDB存储过程实战:聚合框架、脚本、最佳实践,一文全掌握!
【8月更文挑战第24天】MongoDB是一款备受欢迎的文档型NoSQL数据库,以灵活的数据模型和强大功能著称。尽管其存储过程支持不如传统关系型数据库,本文深入探讨了MongoDB在此方面的最佳实践。包括利用聚合框架处理复杂业务逻辑、封装业务逻辑提高复用性、运用JavaScript脚本实现类似存储过程的功能以及考虑集成其他工具提升数据处理能力。通过示例代码展示如何创建订单处理集合并定义验证规则,虽未直接实现存储过程,但有效地演示了如何借助JavaScript脚本处理业务逻辑,为开发者提供更多实用指导。
71 2
|
3月前
|
持续交付 jenkins C#
“WPF与DevOps深度融合:从Jenkins配置到自动化部署全流程解析,助你实现持续集成与持续交付的无缝衔接”
【8月更文挑战第31天】本文详细介绍如何在Windows Presentation Foundation(WPF)项目中应用DevOps实践,实现自动化部署与持续集成。通过具体代码示例和步骤指导,介绍选择Jenkins作为CI/CD工具,结合Git进行源码管理,配置构建任务、触发器、环境、构建步骤、测试及部署等环节,显著提升开发效率和代码质量。
78 0
|
3月前
|
测试技术 C# 开发者
“代码守护者:详解WPF开发中的单元测试策略与实践——从选择测试框架到编写模拟对象,全方位保障你的应用程序质量”
【8月更文挑战第31天】单元测试是确保软件质量的关键实践,尤其在复杂的WPF应用中更为重要。通过为每个小模块编写独立测试用例,可以验证代码的功能正确性并在早期发现错误。本文将介绍如何在WPF项目中引入单元测试,并通过具体示例演示其实施过程。首先选择合适的测试框架如NUnit或xUnit.net,并利用Moq模拟框架隔离外部依赖。接着,通过一个简单的WPF应用程序示例,展示如何模拟`IUserRepository`接口并验证`MainViewModel`加载用户数据的正确性。这有助于确保代码质量和未来的重构与扩展。
89 0
下一篇
无影云桌面