当前位置: 首页 > news >正文

MongoDB聚合:$bucket

$bucket将输入文档按照指定的表达式和边界进行分组,每个分组为一个文档,称为“桶”,每个桶都有一个唯一的_id,其值为文件桶的下线。每个桶中至少要包含一个输入文档,也就是没有空桶。

使用

语法

{$bucket: {groupBy: <表达式>,boundaries: [ <下边界1>, <下边界2>, ... ],default: <literal>,output: {<output1>: { <$accumulator 表达式> },...<outputN>: { <$accumulator 表达式> }}}
}
groupBy

对文档进行分组的表达式。若指定字段路径,需要在字段名前加上美元符号$并用引号引起来,如:$field_name

除非指定了default,否则所有输入文档的groupBy的值都必须在boundaries指定边界的范围内。

boundaries

分组边界数组,数组中相邻的两个值分别作为桶的上下边界,输入文档根据groupBy表达式的值,确定被分配到哪个桶。数组至少要有两个元素,并按照升序从左到右排列,除数值混合类型外(如:[10, NumberLong(20), NumberInt(30)]),数组元素类型必须一致。

举例:

一个数组 [ 0, 5, 10 ] 创建了两个桶:

[0,5),下界为 0,上界为 5。

[5,10),下界为 5,上界为 10。

default

可选,指定缺省桶的_id,不符合boundaries范围的文档都会放在缺省桶内。如果不指定default,所有输入文档的groupBy表达式的值必须落在boundaries区间,否则会抛出异常。

缺省值必须小于boundaries数组中最小的值或大于boundaries数组中的最大值。default值的类型可以不同于boundaries数组元素的类型。

out

可选,指定输出文档内容中除_id字段外要包含的其他字段,指定的字段必须使用汇总(累加器)表达式。

<outputfield1>: { <accumulator>: <expression1> },
...
<outputfieldN>: { <accumulator>: <expressionN> }

如果未指定output文档,默认返回桶内文档数量count字段,如果指定了output文档的字段,则只返回_id和指定的字段,count字段默认不会输出。

例子

按年分桶并对桶的结果进行筛选

创建artists集合并插入下面的记录

db.artists.insertMany([{ "_id" : 1, "last_name" : "Bernard", "first_name" : "Emil", "year_born" : 1868, "year_died" : 1941, "nationality" : "France" },{ "_id" : 2, "last_name" : "Rippl-Ronai", "first_name" : "Joszef", "year_born" : 1861, "year_died" : 1927, "nationality" : "Hungary" },{ "_id" : 3, "last_name" : "Ostroumova", "first_name" : "Anna", "year_born" : 1871, "year_died" : 1955, "nationality" : "Russia" },{ "_id" : 4, "last_name" : "Van Gogh", "first_name" : "Vincent", "year_born" : 1853, "year_died" : 1890, "nationality" : "Holland" },{ "_id" : 5, "last_name" : "Maurer", "first_name" : "Alfred", "year_born" : 1868, "year_died" : 1932, "nationality" : "USA" },{ "_id" : 6, "last_name" : "Munch", "first_name" : "Edvard", "year_born" : 1863, "year_died" : 1944, "nationality" : "Norway" },{ "_id" : 7, "last_name" : "Redon", "first_name" : "Odilon", "year_born" : 1840, "year_died" : 1916, "nationality" : "France" },{ "_id" : 8, "last_name" : "Diriks", "first_name" : "Edvard", "year_born" : 1855, "year_died" : 1930, "nationality" : "Norway" }
])

下面的操作对文档按照year_born字段进行分组放入桶中,并根据桶内文档数量进行筛选:

db.artists.aggregate( [// 阶段1{$bucket: {groupBy: "$year_born",                        // 分组字段boundaries: [ 1840, 1850, 1860, 1870, 1880 ], // 桶边界default: "Other",                             // 边界外的桶的IDoutput: {                                     // 指定桶的输出文档"count": { $sum: 1 },"artists" :{$push: {"name": { $concat: [ "$first_name", " ", "$last_name"] },"year_born": "$year_born"}}}}},// 阶段2{$match: { count: {$gt: 3} } //过滤出文档数量大于3的桶}
] )
阶段1

$bucket阶段对文档根据year_born分组把文档放入桶,桶的边界为:

  • [1840, 1850):下限1840(含),上限1850(不含)。
  • [1850, 1860):下限1840(含),上限1850(不含)。
  • [1860, 1870):下限1840(含),上限1850(不含)。
  • [1870, 1880):下限1840(含),上限1850(不含)。
  • 如果输入文档中year_born字段不存在或者值在边界外,文档将被放到_id值为"other"的缺省桶中。

阶段1的output指定了输出文档的字段:

字段描述
_id包含了桶的边界下限
count桶内文档数量
artists文档数组,包含了桶内所有文章,每个文档的artists字段都包含了拼接后的first_namelast_name,以及`year_born’字段

通过该阶段后,下面的文档进入下个阶段:

{ "_id" : 1840, "count" : 1, "artists" : [ { "name" : "Odilon Redon", "year_born" : 1840 } ] }
{ "_id" : 1850, "count" : 2, "artists" : [ { "name" : "Vincent Van Gogh", "year_born" : 1853 },{ "name" : "Edvard Diriks", "year_born" : 1855 } ] }
{ "_id" : 1860, "count" : 4, "artists" : [ { "name" : "Emil Bernard", "year_born" : 1868 },{ "name" : "Joszef Rippl-Ronai", "year_born" : 1861 },{ "name" : "Alfred Maurer", "year_born" : 1868 },{ "name" : "Edvard Munch", "year_born" : 1863 } ] }
{ "_id" : 1870, "count" : 1, "artists" : [ { "name" : "Anna Ostroumova", "year_born" : 1871 } ] }
阶段2

$match阶段使用count>3的条件,对$bucket阶段out的文档进行筛选,筛选后的结果如下:

{ "_id" : 1860, "count" : 4, "artists" :[{ "name" : "Emil Bernard", "year_born" : 1868 },{ "name" : "Joszef Rippl-Ronai", "year_born" : 1861 },{ "name" : "Alfred Maurer", "year_born" : 1868 },{ "name" : "Edvard Munch", "year_born" : 1863 }]
}

使用$bucket$facet按多个字段分类

使用$facet可以在一个阶段执行多个$bucket聚合。使用mongosh创建artwork集合并添加下面的文档:

db.artwork.insertMany([{ "_id" : 1, "title" : "The Pillars of Society", "artist" : "Grosz", "year" : 1926,"price" : NumberDecimal("199.99") },{ "_id" : 2, "title" : "Melancholy III", "artist" : "Munch", "year" : 1902,"price" : NumberDecimal("280.00") },{ "_id" : 3, "title" : "Dancer", "artist" : "Miro", "year" : 1925,"price" : NumberDecimal("76.04") },{ "_id" : 4, "title" : "The Great Wave off Kanagawa", "artist" : "Hokusai","price" : NumberDecimal("167.30") },{ "_id" : 5, "title" : "The Persistence of Memory", "artist" : "Dali", "year" : 1931,"price" : NumberDecimal("483.00") },{ "_id" : 6, "title" : "Composition VII", "artist" : "Kandinsky", "year" : 1913,"price" : NumberDecimal("385.00") },{ "_id" : 7, "title" : "The Scream", "artist" : "Munch", "year" : 1893/* No price*/ },{ "_id" : 8, "title" : "Blue Flower", "artist" : "O'Keefe", "year" : 1918,"price" : NumberDecimal("118.42") }
])

下面的操作在一个$facet阶段中使用两个$bucket,一个使用price字段,另一个使用year字段分组:

db.artwork.aggregate( [{$facet: {                               // 顶层 $facet 阶段"price": [                            // 输出字段1{$bucket: {groupBy: "$price",            // 分组字段boundaries: [ 0, 200, 400 ],  // 桶边界数组default: "Other",             // 缺省桶Idoutput: {                     // 桶输出内容"count": { $sum: 1 },"artwork" : { $push: { "title": "$title", "price": "$price" } },"averagePrice": { $avg: "$price" }}}}],"year": [                                      // 输出字段2{$bucket: {groupBy: "$year",                        // 分组字段boundaries: [ 1890, 1910, 1920, 1940 ],  // 桶边界数组default: "Unknown",                      // 缺省桶Idoutput: {                                // 桶输出内容"count": { $sum: 1 },"artwork": { $push: { "title": "$title", "year": "$year" } }}}}]}}
] )
方面1

第一个方面按price对输入文档进行分组,桶的边界有:

  • [0,200),含下限0,不含上限200。
  • [200, 400),含下限200,不含上限400。
  • “Other”,缺省桶包含了所有不在以上桶内的文档。

$bucket阶段的输出out文档包含下面的字段:

字段描述
_id桶边界下限值
count桶内文档数量
artwork包含所有艺术品信息的文档数组
averagePrice使用$avg运算符显示水桶中所有艺术品的平均价格。
方面2

第二个方面按year对输入文档进行分组,桶的边界有:

  • [1890, 1910),含下限1890,不含上限1910。
  • [1910, 1920),含下限1890,不含上限1910。
  • [1920, 1940),含下限1890,不含上限1910。
  • “Unknown”,缺省桶包含了所有不在以上桶内的文档。

$bucket阶段的输出out文档包含下面的字段:

字段描述
count桶内文档数量
artwork桶内每件艺术品信息的文件数组。
输出

操作返回下面的结果:

{"price" : [ // Output of first facet{"_id" : 0,"count" : 4,"artwork" : [{ "title" : "The Pillars of Society", "price" : NumberDecimal("199.99") },{ "title" : "Dancer", "price" : NumberDecimal("76.04") },{ "title" : "The Great Wave off Kanagawa", "price" : NumberDecimal("167.30") },{ "title" : "Blue Flower", "price" : NumberDecimal("118.42") }],"averagePrice" : NumberDecimal("140.4375")},{"_id" : 200,"count" : 2,"artwork" : [{ "title" : "Melancholy III", "price" : NumberDecimal("280.00") },{ "title" : "Composition VII", "price" : NumberDecimal("385.00") }],"averagePrice" : NumberDecimal("332.50")},{// Includes documents without prices and prices greater than 400"_id" : "Other","count" : 2,"artwork" : [{ "title" : "The Persistence of Memory", "price" : NumberDecimal("483.00") },{ "title" : "The Scream" }],"averagePrice" : NumberDecimal("483.00")}],"year" : [ // Output of second facet{"_id" : 1890,"count" : 2,"artwork" : [{ "title" : "Melancholy III", "year" : 1902 },{ "title" : "The Scream", "year" : 1893 }]},{"_id" : 1910,"count" : 2,"artwork" : [{ "title" : "Composition VII", "year" : 1913 },{ "title" : "Blue Flower", "year" : 1918 }]},{"_id" : 1920,"count" : 3,"artwork" : [{ "title" : "The Pillars of Society", "year" : 1926 },{ "title" : "Dancer", "year" : 1925 },{ "title" : "The Persistence of Memory", "year" : 1931 }]},{// Includes documents without a year"_id" : "Unknown","count" : 1,"artwork" : [{ "title" : "The Great Wave off Kanagawa" }]}]
}

注意

跟很多阶段类似,$bucket阶段也有100M内存的限制,缺省情况下如果超出100M将会抛出异常。可使用allowDiskUse选项,让聚合管道阶段将数据写入临时文件。

相关文章:

MongoDB聚合:$bucket

$bucket将输入文档按照指定的表达式和边界进行分组&#xff0c;每个分组为一个文档&#xff0c;称为“桶”&#xff0c;每个桶都有一个唯一的_id&#xff0c;其值为文件桶的下线。每个桶中至少要包含一个输入文档&#xff0c;也就是没有空桶。 使用 语法 {$bucket: {groupBy…...

从优化设计到智能制造:生成式AI在可持续性3D打印中的潜力和应用

可持续性是现代工业中一个紧迫的问题&#xff0c;包括 3D 打印领域。为了满足环保制造实践日益增长的需求&#xff0c;3D 打印已成为一种有前景的解决方案。然而&#xff0c;要使 3D 打印更具可持续性&#xff0c;还存在一些需要解决的挑战。生成式人工智能作为一股强大的力量&…...

vue3 响应式api中特殊的api

系列文章目录 TypeScript 从入门到进阶专栏 文章目录 系列文章目录一、shallowRef()二、triggerRef()三、customRef()四、shallowReactive()五、shallowReadonly()六、toRaw()七、markRaw()八、effectScope()九、getCurrentScope() 一、shallowRef() shallowRef()是一个新的响…...

【大厂算法面试冲刺班】day2:合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 递归 class Solution {public ListNode mergeTwoLists(ListNode l1, ListNode l2) {if (l1 null) {return l2;}else if (l2 null) {return l1;}else if (l1.val < l2.…...

【JaveWeb教程】(19) MySQL数据库开发之 MySQL数据库操作-DML 详细代码示例讲解

目录 3. 数据库操作-DML3.1 增加(insert)3.2 修改(update)3.3 删除(delete)3.4 总结 3. 数据库操作-DML DML英文全称是Data Manipulation Language(数据操作语言)&#xff0c;用来对数据库中表的数据记录进行增、删、改操作。 添加数据&#xff08;INSERT&#xff09;修改数据…...

Web前端篇——ElementUI之el-scrollbar + el-backtop + el-timeline实现时间轴触底刷新和一键返回页面顶部

ElementUI之el-scrollbar el-backtop el-timeline实现时间轴触底刷新和一键返回页面顶部。 背景&#xff1a;ElementUI的版本&#xff08;vue.global.js 3.2.36&#xff0c; index.css 2.4.4&#xff0c; index.full.js 2.4.4&#xff09; 废话不多说&#xff0c;先看动…...

CAS-ABA问题编码实战

多线程情况下演示AtomicStampedReference解决ABA问题 package com.nanjing.gulimall.zhouyimo.test;import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicStampedReference;/*** @author zho…...

Linux 常用进阶指令

我是南城余&#xff01;阿里云开发者平台专家博士证书获得者&#xff01; 欢迎关注我的博客&#xff01;一同成长&#xff01; 一名从事运维开发的worker&#xff0c;记录分享学习。 专注于AI&#xff0c;运维开发&#xff0c;windows Linux 系统领域的分享&#xff01; 其他…...

windows通过ssh连接Liunx服务器并实现上传下载文件

连接ssh 输入&#xff1a;ssh空格用户名ip地址&#xff0c;然后按Enter 有可能出现下图提示&#xff0c;输入yes 回车即可 输入 password &#xff0c;注意密码是不显示的&#xff0c;输入完&#xff0c;再按回车就行了 以上是端口默认22情况下ssh连接&#xff0c;有些公司它…...

【K8S 存储卷】K8S的存储卷+PV/PVC

目录 一、K8S的存储卷 1、概念&#xff1a; 2、挂载的方式&#xff1a; 2.1、emptyDir&#xff1a; 2.2、hostPath&#xff1a; 2.3、NFS共享存储&#xff1a; 二、PV和PVC&#xff1a; 1、概念 2、请求方式 3、静态请求流程图&#xff1a; 4、PV和PVC的生命周期 5、…...

工业智能网关如何保障数据通信安全

工业智能网关是组成工业物联网的重要设备&#xff0c;不仅可以起到数据交换、通信、边缘计算的功能&#xff0c;还可以发挥数据安全保障功能&#xff0c;保障工业物联网稳定、可持续。本篇就为大家简单介绍一下工业智能网关增强和确保数据通信安全的几种措施&#xff1a; 1、软…...

基于Springboot的课程答疑系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的课程答疑系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&…...

操作系统 内存相关

0 内存 cpu和内存的关系 内存覆盖 内存的覆盖是一种在程序运行时将部分程序和数据分为固定区和覆盖区的技术。这种技术的主要目的是为了解决程序较大&#xff0c;无法一次性装入内存导致无法运行的问题。 具体来说&#xff0c;内存的覆盖技术将用户空间划分为以下两个部分&…...

【模拟IC学习笔记】 PSS和Pnoise仿真

目录 PSS Engine Beat frequency Number of harmonics Accuracy Defaults Run tranisent?的3种设置 Pnoise type noise Timeaverage sampled(jitter) Edge Crossing Edge Delay Sampled Phase sample Ratio 离散时间网络(开关电容电路)的噪声仿真方法 PSS PSS…...

IPv6邻居发现协议(NDP)---路由发现

IPv6路由发现(前缀公告) 邻居发现 邻居发现协议NDP(Neighbor Discovery Protocol)是IPv6协议体系中一个重要的基础协议。邻居发现协议替代了IPv4的ARP(Address Resolution Protocol)和ICMP路由器发现(Router Discovery),它定义了使用ICMPv6报文实现地址解析,跟踪邻…...

OpenPLC v3 代码结构

OpenPLC v3 是一个基于 C 的开源实时自动化平台&#xff0c;主要用于控制和自动化行业中的设备。该项目具有以下主要模块&#xff1a; 1. Core&#xff1a;核心模块&#xff0c;提供数据结构和算法实现。 2. Master&#xff1a;主设备模块&#xff0c;实现与从设备通信的接口。…...

安全防御之备份恢复技术

随着计算机和网络的不断普及&#xff0c;人们更多的通过网络来传递大量信息。在网络环境下&#xff0c;还有各种各样的病毒感染、系统故障、线路故障等&#xff0c;使得数据信息的安全无法得到保障。由于安全风险的动态性&#xff0c;安全不是绝对的&#xff0c;信息系统不可能…...

条款39:明智而审慎地使用private继承

1.前言 在之前挑款32曾讨论了C如何将public继承视为is-a关系&#xff0c;在那个例子中我们有个继承体系&#xff0c;其中class Student以public形式继承class Person&#xff0c;于是编译器在必要时刻将Student转换为Persons。。现在&#xff0c;我在以原先那个例子&#xff0…...

【数据库原理】(20)查询优化概述

查询优化是关系数据库系统设计和实现中的核心部分&#xff0c;对提高数据库性能、减少资源消耗、提升用户体验有着重要影响。虽然挑战重重&#xff0c;但凭借坚实的理论基础和先进的技术手段&#xff0c;关系数据库在查询优化方面有着广阔的发展空间。 一.查询中遇到的问题 数…...

FineBI实战项目一(18):每小时上架商品个数分析开发

点击新建组件&#xff0c;创建每小时上架商品个数组件。 选择线图&#xff0c;拖拽cnt&#xff08;总数&#xff09;到纵轴&#xff0c;拖拽hourStr到横轴。 修改横轴和纵轴的文字。 调节连线样式。 添加组件到仪表板。...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

IT供电系统绝缘监测及故障定位解决方案

随着新能源的快速发展&#xff0c;光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域&#xff0c;IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选&#xff0c;但在长期运行中&#xff0c;例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建

华为云FlexusDeepSeek征文&#xff5c;DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色&#xff0c;华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型&#xff0c;能助力我们轻松驾驭 DeepSeek-V3/R1&#xff0c;本文中将分享如何…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

MySQL 部分重点知识篇

一、数据库对象 1. 主键 定义 &#xff1a;主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 &#xff1a;确保数据的完整性&#xff0c;便于数据的查询和管理。 示例 &#xff1a;在学生信息表中&#xff0c;学号可以作为主键&#xff…...

django blank 与 null的区别

1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是&#xff0c;要注意以下几点&#xff1a; Django的表单验证与null无关&#xff1a;null参数控制的是数据库层面字段是否可以为NULL&#xff0c;而blank参数控制的是Django表单验证时字…...

从面试角度回答Android中ContentProvider启动原理

Android中ContentProvider原理的面试角度解析&#xff0c;分为​​已启动​​和​​未启动​​两种场景&#xff1a; 一、ContentProvider已启动的情况 1. ​​核心流程​​ ​​触发条件​​&#xff1a;当其他组件&#xff08;如Activity、Service&#xff09;通过ContentR…...