MongoDB聚合操作-02

news2024/12/30 2:40:43

一、聚合操作

聚合操作处理数据记录并返回计算结果。 聚合操作组值来自多个文档,可以对分组数据执行 各种操作以返回单个结果。 聚合操作包含三类:单一作用聚合、聚合管道、MapReduce。
      单一作用聚合:提供了对常见聚合过程的简单访问,操作都从单个集合聚合文 档。
     聚合管道是一个数据聚合的框架,模型基于数据处理流水线的概念。 文档进入多 级管道,将 文档转换为聚合结果。
     MapReduce操作具有两个阶段:处理每个文档并向每个输入文档发射一个或多个对象的map阶段,以及reduce组合map操作的输出阶段。

1、单一作用聚合

     MongoDB提供 db.collection.estimatedDocumentCount(), db.collection.count(), db.collection.distinct() 这类单一作用的聚合函数。 所有这些操作都聚合来自单个集合的
文档。虽然这些操作提供了对公共聚合过程的简单访问,但它们缺乏聚合管道和mapReduce的灵活性和功能。

 

db.collection.estimatedDocumentCou
nt()
返回集合或视图中所有文档的计数
db.collection.count()
返回与find()集合或视图的查询匹配的文档计数 。等同于
db.collection.find(query).count()构造
db.collection.distinct()
在单个集合或视图中查找指定字段的不同值,并在数组中
返回结果。
#检索books集合中所有文档的计数
 db.books.estimatedDocumentCount()
#计算与查询匹配的所有文档
 db.books.count({favCount:{$gt:50}})
#返回不同type的数组
 db.books.distinct("type")
#返回收藏数大于90的文档不同type的数组
 db.books.distinct("type",{favCount:{$gt:90}})
注意:在分片群集上,如果存在孤立文档或正在进行块迁移,则db.collection.count()
没有查询谓词可能导致计数不准确。要避免这些情况,请在分片群集上使用
db.collection.aggregate()方法。

2、聚合管道

什么是 MongoDB 聚合框架

MongoDB 聚合框架(Aggregation Framework)是一个计算框架 ,它可以: 作用在一个或几个集合上; 对集合中的数据进行的一系列运算; 将这些数据转化为期望的形式;
从效果而言,聚合框架相当于 SQL 查询中的GROUP BY、 LEFT OUTER JOIN 、 AS等。
管道(Pipeline)和阶段( Stage) 整个聚合运算过程称为管道(Pipeline),它是由多个阶段(
Stage)组成的 , 每个管道: 接受一系列文档(原始数据); 每个阶段对这些文档进行一系列运算; 结果文档输出给下一个阶段;

聚合管道操作语法
pipeline = [$stage1, $stage2, ...$stageN];
db.collection.aggregate(pipeline, {options})
        pipelines 一组数据聚合阶段。除$out、$Merge和$geonear阶段之外,每个阶 段都可以在管道中出现多次。
       options 可选,聚合操作的其他参数。包含:查询计划、是否使用临时文件、 游标、最大操作时间、读写策略、强制索引等等

 

常用的管道聚合阶段

聚合管道包含非常丰富的聚合阶段,下面是最常用的聚合阶段

 

数据准备

准备数据集,执行脚本
var tags = ["nosql","mongodb","document","developer","popular"];
 var types = ["technology","sociality","travel","novel","literature"];
 var books=[];
 for(var i=0;i<50;i++){
 var typeIdx = Math.floor(Math.random()*types.length);
 var tagIdx = Math.floor(Math.random()*tags.length);
 var tagIdx2 = Math.floor(Math.random()*tags.length);
 var favCount = Math.floor(Math.random()*100);
 var username = "xx00"+Math.floor(Math.random()*10);
 var age = 20 + Math.floor(Math.random()*15);
 var book = {
 title: "book‐"+i,
 type: types[typeIdx],
 tag: [tags[tagIdx],tags[tagIdx2]],
 favCount: favCount,
 author: {name:username,age:age}
 };
 books.push(book)
 }
 db.books.insertMany(books);

$project

投影操作 , 将原始字段投影成指定名称, 如将集合中的 title 投影成 name
db.books.aggregate([{$project:{name:"$title"}}])
$project 可以灵活控制输出文档的格式 ,也可以剔除不需要的字段
db.books.aggregate([{$project:{name:"$title",_id:0,type:1,author:1}}])
从嵌套文档中排除字段
db.books.aggregate([
 {$project:{name:"$title",_id:0,type:1,"author.name":1}}
])
 或者
db.books.aggregate([
 {$project:{name:"$title",_id:0,type:1,author:{name:1}}}
])

$match

      $match用于对文档进行筛选 ,之后可以在得到的文档子集上做聚合,$match可以使
用除了地理空间之外的所有常规查询操作符, 在实际应用中尽可能将$match放在管道的前
面位置 。这样有两个好处:一是可以快速将不需要的文档过滤掉,以减少管道的工作量;二
是如果再投射和分组之前执行$match,查询可以使用索引。
db.books.aggregate([{$match:{type:"technology"}}])
     筛选管道操作和其他管道操作配合时候时,尽量放到开始阶段,这样可以减少后续管道
操作符要操作的文档数,提升效率
  
   
db.books.aggregate([
 {$match:{type:"technology"}},
 {$project:{name:"$title",_id:0,type:1,author:{name:1}}}
 ])

$count

 计数并返回与查询匹配的结果数

db.books.aggregate([
   {$match:{type:"technology"}},
   {$count: "type_count"}
 ])
$match阶段筛选出type匹配technology的文档,并传到下一阶段;
$count 阶段返回聚合管道中剩余文档的计数,并将该值分配给type_count

$group

按指定的表达式对文档进行分组,并将每个不同分组的文档输出到下一个阶段 。输出文档包
含一个_id字段,该字段按键包含不同的组。
输出文档还可以包含计算字段,该字段保存由$group的_id字段分组的一些accumulator表
达式的值。 $group不会输出具体的文档而只是统计信息.
{ $group: { _id: <expression>, <field1>: { <accumulator1> : <expression1>
}, ... } }
1、_id字段是必填的;但是,可以指定_id值为null来为整个输入文档计算累计值。
2、剩余的计算字段是可选的,并使用<accumulator>运算符进行计算。
3、_id和<accumulator>表达式可以接受任何有效的 表达式
accumulator操作符
名称
描述 类比sql
$avg
计算均值
avg
$first
返回每组第一个文档,如果有排序,按照排序,如果没有按照默认的 存储的顺序的第一个文档。
limit0,1
$last
返回每组最后一个文档,如果有排序,按照排序,如果没有按照默认 的存储的顺序的最后个文档
$max
根据分组,获取集合中所有文档对应值得最大值
max
$min
根据分组,获取集合中所有文档对应值得最小值。
min
$pus
将指定的表达式的值添加到一个数组中
$addToSet
将表达式的值添加到一个集合中(无重复值,无序)
$sum
计算总和
sum
$stdDevPop
返回输入值的总体标准偏差(population standard deviation)
$stdDevSamp
返回输入值的样本标准偏差(the sample standard deviation)
$group阶段的内存限制为100M。默认情况下,如果stage超过此限制,$group将产生错
误。 但是,要允许处理大型数据集,请将allowDiskUse选项设置为true以启用$group操作
以写入临时文件。
book的数量,收藏总数和平均值
db.books.aggregate([
 {$group:{_id:null,count:{$sum:1},pop:{$sum:"$favCount"},avg:{$avg:"$favCount"}}}
 ])
统计每个作者的book收藏总数
db.books.aggregate([
 {$group:{_id:"$author.name",pop:{$sum:"$favCount"}}}
 ])
统计每个作者的每本book的收藏数
db.books.aggregate([
 {$group:{_id:{name:"$author.name",title:"$title"},pop:{$sum:"$favCount"}}}
 ])
每个作者的book的type合集
db.books.aggregate([
  {$group:{_id:"$author.name",types:{$addToSet:"$type"}}}
])

$unwind

可以将数组拆分为单独的文档
{
 $unwind:
 {
 #要指定字段路径,在字段名称前加上$符并用引号括起来。
 path: <field path>,
 #可选,一个新字段的名称用于存放元素的数组索引。该名称不能以$开头。
 includeArrayIndex: <string>,
 #可选,default :false,若为true,如果路径为空,缺少或为空数组,则$unwind输出文档
 preserveNullAndEmptyArrays: <boolean>
 } }
姓名为xx006的作者的book的tag数组拆分为多个文档
db.books.aggregate([
 {$match:{"author.name":"xx006"}},
 {$unwind:"$tag"}
 ])

 db.books.aggregate([
 {$match:{"author.name":"xx006"}}
 ])
每个作者的book的tag合集
db.books.aggregate([
 {$unwind:"$tag"},
 {$group:{_id:"$author.name",types:{$addToSet:"$tag"}}}
 ])

$limit

db.books.aggregate([
 {$limit : 5 }
 ])
此操作仅返回管道传递给它的前5个文档。 $limit对其传递的文档内容没有影响。
注意:当$sort在管道中的$limit之前立即出现时,$sort操作只会在过程中维持前n个结
,其中n是指定的限制,而MongoDB只需要将n个项存储在内存中。

$skip

跳过进入stage的指定数量的文档,并将其余文档传递到管道中的下一个阶段
db.books.aggregate([
 {$skip : 5 }
 ])
此操作将跳过管道传递给它的前5个文档。 $skip对沿着管道传递的文档的内容没有影响。

$sort

对所有输入文档进行排序,并按排序顺序将它们返回到管道。
语法:
{ $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }
要对字段进行排序,请将排序顺序设置为1或-1,以分别指定升序或降序排序,如下例所
示:
db.books.aggregate([
 {$sort : {favCount:‐1,title:1}}
 ])

$lookup

Mongodb 3.2版本新增,主要用来实现多表关联查询, 相当关系型数据库中多表关联查
询。 每个输入待处理的文档,经过$lookup 阶段的处理,输出的新文档中会包含一个新生
成的数组 (可根据需要命名新key )。数组列存放的数据是来自被Join集合的适配文档,如
果没有,集合为空(即 为[ ])
语法:
db.collection.aggregate([{
 $lookup: {
 from: "<collection to join>",
 localField: "<field from the input documents>",
 foreignField: "<field from the documents of the from collection>",
 as: "<output array field>"
  }
 })
from
同一个数据库下等待被Join的集合。
localField
源集合中的match值,如果输入的集合中,某文档没有 localField 这个Key(Field),在处理的过程中,会默认为此文档含 有 localField:null的键值对。
foreignField
待Join的集合的match值,如果待Join的集合中,文档没有foreignField 值,在处理的过程中,会默认为此文档含有 foreignField:null的键值对。
as
为输出文档的新增值命名。如果输入的集合中已存在该值,则会覆盖掉
注意:null = null 此为真
其语法功能类似于下面的伪SQL语句:
SELECT *, <output array field>
 FROM collection
 WHERE <output array field> IN (SELECT *
 FROM <collection to join>
 WHERE <foreignField>= <collection.localField>);
案例
数据准备
db.customer.insert({customerCode:1,name:"customer1",phone:"13112345678",address:"test1"})
db.customer.insert({customerCode:2,name:"customer2",phone:"13112345679",address:"test2"})
db.order.insert({orderId:1,orderCode:"order001",customerCode:1,price:200})
db.order.insert({orderId:2,orderCode:"order002",customerCode:2,price:400})
db.orderItem.insert({itemId:1,productName:"apples",qutity:2,orderId:1})
db.orderItem.insert({itemId:2,productName:"oranges",qutity:2,orderId:1})
db.orderItem.insert({itemId:3,productName:"mangoes",qutity:2,orderId:1})
db.orderItem.insert({itemId:4,productName:"apples",qutity:2,orderId:2})
db.orderItem.insert({itemId:5,productName:"oranges",qutity:2,orderId:2})
db.orderItem.insert({itemId:6,productName:"mangoes",qutity:2,orderId:2})
关联查询
db.customer.aggregate([
 {$lookup: {
    from: "order",
    localField: "customerId",
    foreignField: "customerId",
    as: "customerOrder"
    }
  }
 ])

 db.order.aggregate([
 {$lookup: {
 from: "customer",
 localField: "customerCode",
 foreignField: "customerCode",
 as: "curstomer"
 }
},
 {$lookup: {
 from: "orderItem",
 localField: "orderId",
 foreignField: "orderId",
 as: "orderItem"
 }
 } ])
聚合操作案例1
统计每个分类的book文档数量
db.books.aggregate([
 {$group:{_id:"$type",total:{$sum:1}}},
 {$sort:{total:‐1}}
 ])
标签的热度排行,标签的热度则按其关联book文档的收藏数( favCount)来计算
db.books.aggregate([
 {$match:{favCount:{$gt:0}}},
 {$unwind:"$tag"},
 {$group:{_id:"$tag",total:{$sum:"$favCount"}}},
 {$sort:{total:‐1}}
 ])
1. $match阶段:用于过滤favCount=0的文档。
2. $unwind阶段:用于将标签数组进行展开,这样一个包含3个标签的文档会被拆解 为3个条目。
3. $group阶段:对拆解后的文档进行分组计算,$sum:"$favCount"表示按 favCount字段进行累加。
4. $sort阶段:接收分组计算的输出,按total得分进行排序。
统计book文档收藏数[0,10),[10,60),[60,80),[80,100),[100,+∞)
db.books.aggregate([{
 $bucket:{
 groupBy:"$favCount",
 boundaries:[0,10,60,80,100],
 default:"other",
 output:{"count":{$sum:1}}
 }
 }])

二、MapReduce

MapReduce操作将大量的数据处理工作拆分成多个线程并行处理,然后将结果合并在一
起。MongoDB提供的Map-Reduce非常灵活,对于大规模数据分析也相当实用。
MapReduce具有两个阶段:
1. 将具有相同Key的文档数据整合在一起的map阶段
2. 组合map操作的结果进行统计输出的reduce阶段
从MongoDB 5.0开始,map-reduce操作已被弃用。 聚合管道比映射-reduce操作提供更
好的性能和可用性。Map-reduce操作可以使用聚合管道操作符重写,例如$group、
$merge等

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/656295.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

马原第二章复习 1.实践和认识 80-109

实践 (一) 实践的本质 人类能动改造世界的客观物质活动 实践具有三个基本特征 客观实在性(体现在构成实践的诸多要素) 主观能动性(实践是一种有目的有计划的活动) 客观物质性 (二) 实践的基本结构 实践主体 实践客体 实践中介 辨析:实践客体不等于客观事物 客观事物只有…

市场份额被微软步步蚕食,Zoom已到生死存亡关头

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 Zoom (ZM)这几年一直在竞争加剧、视频会议市场增长放缓以及投资者对该公司的高期望下艰难挣扎。 虽然Zoom的股价已较高点时大幅下跌&#xff08;Zoom的股价已较2021年8月的高点暴跌了80%以上&#xff09;&#xff0c;但猛兽…

day57|动态规划17-最长回文子串问题

回文子串&#xff1a;强调连续 回文子序列&#xff1a;不强调连续 647. 回文子串的个数 暴力思路&#xff1a;三层for循环双指针思路&#xff1a;动态规划dp数组 dp[i][j]&#xff1a; 根据字符串的形式和所解决的问题确定dp数组的形式和含义。 递归公式&#xff08;分情况讨…

B046-cms01-后台搭建 界面修改 分页 GirdManager

目录 cms项目介绍Maven跳转到后台首页视图解析器页面和静态资源准备资源分布controller控制器 跳转到文章展示页面index.JSPArticleControllerarticle.jsp gridManager初体验和显示文章数据时间和是否启用显示Articlearticle.jsp 展示文章类型ArticleServiceImplarticle.jsp 按…

短视频seo源码部署--LINUX环境

抖音矩阵系统源码/抖音seo矩阵系统/抖音账号矩阵源码/短视频seo源码部署 *基于PHP语言&#xff0c;linux环境&#xff0c;MVC框架进行研发&#xff0c;开源部署 开源性质使得用户可以根据自己的需求对其进行二次开发和定制。然而&#xff0c;对于该软件的部署却是一项非常关键…

Python异步编程之web框架 异步vs同步 Redis并发对比

1|0测试基本信息 主题&#xff1a;比较异步框架和同步框架在RedisIO操作的性能差异python版本&#xff1a;python 3.8数据库&#xff1a;redis 5.0.7压测工具&#xff1a;locustweb框架&#xff1a;同步&#xff1a;flask 异步&#xff1a;starlette请求并发量: 模拟10个用户服…

ubuntu下,安装配置CUDA

一、下载文件。 到下面的官网链接&#xff0c;下载你自己需要的版本。我喜欢11.7 CUDA Toolkit Archive | NVIDIA Developer 二、安装 可能的错误&#xff1a; Failed to verify gcc version. --Linux安装CUDA GCC版本不兼容 sudo sh cuda_xxxxxxxxxxxxxx_linux.run --overr…

【vue+websocket】vue本地链接websocket正常,线上部署websocket 无法加载响应数据【已解决】

1.nginx配置&#xff0c;进行反向代理 location /链接websocket的名称 {proxy_pass http://localhost:websocket端口号/链接websocket的名称;proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "Upgrade"; }2.开放websoc…

Ansible源码学习(一)

一、背景说明 基于Ansible1.1源码学习 二、目录结构 ansible核心目录 ansible ├─bin # 入口命令 │ ├─ansible │ ├─ansible-doc │ ├─ansible-playbook │ ├─ansible-pull ├─lib # 核心代码 │ └─ansible │ ├─callback_plugins …

Netty核心技术六--Netty核心模块组件

1. Bootstrap、ServerBootstrap Bootstrap 意思是引导&#xff0c;一个 Netty 应用通常由一个Bootstrap 开始&#xff0c;主要作用是配置整个 Netty 程序&#xff0c;串联各个组件&#xff0c;Netty 中 Bootstrap 类是客户端程序的启动引导类&#xff0c;ServerBootstrap 是服…

【Linux】天天直接IO?我说停停,不如试试文件缓冲区

系列文章 收录于【Linux】文件系统 专栏 关于文件描述符与文件重定向的相关内容可以移步 文件描述符与重定向操作。 可以到 浅谈文件原理与操作 了解文件操作的系统接口。 目录 系列文章 揭秘C库文件结构体 文件缓冲区 为什么需要文件缓冲区 刷新机制 内核文件缓冲区…

java基础(多线程)-共享资源并发问题以及synchronized解决方案

一、共享资源带来的问题 class ThreadProblem{static int counter 0;public static void testThread(){Thread t1 new Thread(()-> {for (int i 0; i < 5000; i) {counter;}},"t1");Thread t2 new Thread(()-> {for (int i 0; i < 5000; i) {count…

【VMD-LSTM】变分模态分解-长短时记忆神经网络研究(Python代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

主动降噪技术的运用及其展望---【其利天下技术】

降噪耳机想必大家是听说过的&#xff0c;那么什么是降噪耳机呢&#xff1f;降噪耳机的降噪是如何实现的呢&#xff1f; 在很多年前&#xff0c;我想大家肯定认为降噪耳机不就是做得比较帖耳&#xff0c;尽量把声波能量隔离不让进入人耳吗&#xff1f;搞得这么神秘干吗呢&#…

猿辅导基于 EMR StarRocks 的 OLAP 演进之路

摘要&#xff1a;猿辅导大数据平台团队负责人申阳分享了猿辅导基于 StarRocks 的 OLAP 演进之路。主要包括以下几大部分&#xff1a; 数据需求产生OLAP 选型StarRocks 的优势业务场景和技术方案基础建设 Tips&#xff1a;点击「阅读原文」查看原文视频 1► 数据需求产生 猿辅导…

【Linux】进程间通信(1)——匿名管道

文章目录 前言进程间通信的目的进程间通信的发展进程间通信分类管道什么是管道&#xff1f;站在内核角度-管道本质匿名管道pipe函数管道的特点&#xff08;重要&#xff09;用fork来共享管道原理匿名管道的使用步骤管道的读写规则管道的四种场景 如何使用管道进行进程间通信&am…

【Vue3学习】Vuex 状态管理 store

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 库。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。 安装 npm npm install vuexnext --saveyarn npm install vuexnext --save基本使用 1&#xff09;创建…

Kubernetes初认识

系列文章目录 文章目录 系列文章目录一、Kubernetes初认识1.k8s的特性2.K8S架构3.Kubernetes工作流程 二、K8S创建Pod流程1.详细版2.简单版 总结 一、Kubernetes初认识 1.k8s的特性 弹性伸缩&#xff1a;使用命令、UI或者基于CPU使用情况自动快速扩容和缩容应用程序实例&…

磁盘调度算法及其应用

导读&#xff1a; 磁盘调度是计算机系统中的重要问题之一。在多个进程同时访问磁盘时&#xff0c;合理的磁盘调度算法可以优化磁盘访问顺序&#xff0c;提高系统性能。本文将介绍磁盘调度算法的基本思想&#xff0c;并通过一个实验来模拟不同调度算法的运行过程。 正文&#…

如何翻译 Markdown 文件?-2-几种商业及开源解决方案介绍

背景 近期在搭建英文博客-<e-whisper.com>, 需要对现有的所有中文 Markdown 翻译为英文。 需求如下&#xff1a; 将 Markdown 文件从中文 (zh-CN) 翻译为英文 (en)翻译后要保留 Markdown 的完整格式部分 Markdown block 不需要翻译&#xff0c;如&#xff1a;front-ma…