mongodb在Java中条件分组聚合查询并且分页(时间戳,按日期分组,年月日...)

news/2024/9/19 4:49:05/ 标签: mongodb, java, 数据库

废话不多说,先看效果图:

  • SQL查询结果示例:
    在这里插入图片描述
  • 多种查询结果示例:
    在这里插入图片描述

原SQL:

db.getCollection("hbdd_order").aggregate([{// 把时间戳格式化$addFields: {orderDate: {"$dateToString": {"format": "%Y-%m-%d","date": {"$toDate": "$hzdd_order_addtime"}}}}},{$match: {// 筛选条件hzdd_order_addtime: {$gte: 1722441600000,$lt: 1725120000000}}},{// 按格式过的时间分组$group: {"_id": "$orderDate",paidAmount: {$sum: { // 统计$cond: [{ // 条件类似if true =1 else =0$eq: ["$hzdd_order_ispay", 1]}, "$hzdd_order_amount", 0]}},paidCount: {$sum: {$cond: [{$eq: ["$hzdd_order_ispay", 1]}, 1, 0]}},unpaidAmount: {$sum: {$cond: [{$eq: ["$hzdd_order_ispay", 0]}, "$hzdd_order_amount", 0]}},unpaidCount: {$sum: {$cond: [{$eq: ["$hzdd_order_ispay", 0]}, 1, 0]}}}},{$project: {date: "$_id",paidAmount: 1,paidCount: 1,unpaidAmount: 1,unpaidCount: 1}},{$sort: { // 排序date: 1}}
]);

Java语句:

代码中多了些内容,但是和SQL语句大差不差
(懒得替换类名,大家看到陌生的类就是自己建的)

java">import com.mongodb.client.result.UpdateResult;
import jodd.util.StringUtil;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;public Page<OrderStatVo> orderStatistical(OrderStatQuery query) { Pageable pageable = PageRequest.of(query.getPageNum() - 1, query.getPageSize());MongoTemplate mongoTemplate = mongoFactory.mongoTemplate(OrderConstants.ORDER_DB);// 时间筛选Long startTime = query.getStartTime();Long endTime = query.getEndTime();// 区分 1年,2月,3日int type = query.getType();// 按商家idString shopId = query.getShopId();// 按code筛选Integer areaCode = query.getAreaCode();Integer provinceCode = query.getProvinceCode();Integer cityCode = query.getCityCode();Integer countyCode = query.getCountyCode();// 基础匹配条件:按年初和年末 时间戳Criteria baseCriteria = new Criteria();// 额外的筛选条件List<Criteria> additionalCriteria = new ArrayList<>();if (startTime != null && endTime != null) {additionalCriteria.add(Criteria.where("hzdd_order_addtime").gte(startTime).lt(endTime));}if (StringUtil.isNotEmpty(shopId)) {additionalCriteria.add(Criteria.where("hzdd_order_sjid").is(shopId));}if (areaCode != null && areaCode != 0) {additionalCriteria.add(Criteria.where("hzdd_order_area_code").is(areaCode));}if (provinceCode != null && provinceCode != 0) {additionalCriteria.add(Criteria.where("hzdd_order_province_code").is(provinceCode));}if (cityCode != null && cityCode != 0) {additionalCriteria.add(Criteria.where("hzdd_order_city_code").is(cityCode));}if (countyCode != null && countyCode != 0) {additionalCriteria.add(Criteria.where("hzdd_order_county_code").is(countyCode));}// 合并所有条件if (!additionalCriteria.isEmpty()) {baseCriteria.andOperator(additionalCriteria.toArray(new Criteria[0]));}// 构建匹配操作MatchOperation matchOperation = Aggregation.match(baseCriteria);// 添加字段操作,将 Unix 时间戳转换为日期字符串String expression = switch (type) {case 1 -> "{$dateToString: { format: '%Y', date: { $toDate: '$hzdd_order_addtime' }}}";case 2 -> "{$dateToString: { format: '%Y-%m', date: { $toDate: '$hzdd_order_addtime' }}}";case 3 -> "{$dateToString: { format: '%Y-%m-%d', date: { $toDate: '$hzdd_order_addtime' }}}";default -> "{$dateToString: { format: '%Y-%m-%d', date: { $toDate: '$hzdd_order_addtime' }}}";};AddFieldsOperation addFieldsOperation = Aggregation.addFields().addField("orderDate").withValueOfExpression(expression).build();// 分组操作GroupOperation groupOperation = Aggregation.group("orderDate").sum(ConditionalOperators.Cond.when(Criteria.where("hzdd_order_ispay").is(1)).then("$hzdd_order_amount").otherwise(0)).as("paidAmount").sum(ConditionalOperators.Cond.when(Criteria.where("hzdd_order_ispay").is(1)).then(1).otherwise(0)).as("paidCount").sum(ConditionalOperators.Cond.when(Criteria.where("hzdd_order_ispay").is(0)).then("$hzdd_order_amount").otherwise(0)).as("unpaidAmount").sum(ConditionalOperators.Cond.when(Criteria.where("hzdd_order_ispay").is(0)).then(1).otherwise(0)).as("unpaidCount");// 投影操作ProjectionOperation projectionOperation = Aggregation.project().and("_id").as("date").andInclude("paidAmount", "paidCount", "unpaidAmount", "unpaidCount");// 排序操作SortOperation sortOperation = Aggregation.sort(Sort.Direction.ASC, "date");// 分页操作SkipOperation skipOperation = Aggregation.skip((long) pageable.getPageNumber() * pageable.getPageSize());LimitOperation limitOperation = Aggregation.limit(pageable.getPageSize());// 构建不包含分页的聚合查询以获取总条数Aggregation countAggregation = Aggregation.newAggregation(matchOperation,addFieldsOperation,groupOperation,Aggregation.group("orderDate").count().as("totalCount"), // 添加计数操作Aggregation.project("totalCount").andExclude("_id") // 只包含 totalCount 字段);// 执行聚合查询以获取总条数AggregationResults<Document> totalCountResults = mongoTemplate.aggregate(countAggregation, "hbdd_order", Document.class);Document document = totalCountResults.getMappedResults().stream().findFirst().orElse(null);int total = document != null ? (int) document.get("totalCount") : 0;// 构建包含分页的聚合查询Aggregation aggregation = Aggregation.newAggregation(matchOperation,addFieldsOperation,groupOperation,projectionOperation,sortOperation,skipOperation,limitOperation);// 第二个参数是文档名(表名),第三个参数是接收的类,字段对应上面代码中的as别名字段AggregationResults<OrderStatVo> results = mongoTemplate.aggregate(aggregation, "hbdd_order", OrderStatVo.class);List<OrderStatVo> everyDayOrderStats = results.getMappedResults();// 分页操作return new PageImpl<>(everyDayOrderStats, pageable, total);}

** OrderStatQuery 类就不展示了,就是传值进来的筛选条件 **

OrderStatVo类
java">import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;@Data
@Schema(description = "订单统计")
public class OrderStatVo {@Schema(description = "周期")private String date;@Schema(description = "已支付金额")private Double paidAmount;@Schema(description = "已支付订单数")private Long paidCount;@Schema(description = "未支付金额")private Double unpaidAmount;@Schema(description = "未支付订单数")private Long unpaidCount;}
Java中使用mongoDB小技巧:

配置文件中加上下面这行,可以打印出mongo的SQL语句

logging:level:org.springframework.data.mongodb.core.MongoTemplate: DEBUG

http://www.ppmy.cn/news/1520676.html

相关文章

51单片机-独立按键

时间&#xff1a;2024.8.28 作者&#xff1a;Whappy 目的&#xff1a;学习51单片机 代码&#xff1a; #include <REGX52.H> #include "intrins.h"void Delay1ms(unsigned int xms) //11.0592MHz {unsigned char i, j;while(xms--){_nop_();i 2;j 199;do{…

ORA-01186: file 201 failed verification tests

环境&#xff1a;oracle11.2.0.4RACASMred hat6.1x64 主库两节点RAC&#xff0c;备库也为两节点RAC。 备库启用为实时应用查询。日志应用等都是正常的。 主库asm group如下&#xff1a; ASMCMD> ls CRS/DATA/ FRA/ 备库asm group如下&#xff1a; ASMCMD> ls CRS/SDATA/ …

西北工业大学oj-打印杨辉三角

用函数编程计算并输出如图所示的杨辉三角&#xff0c;行数由用户输入。 这道题就很简单了知道杨辉三角的规律&#xff0c;前后都是1&#xff0c;中间数字等于左上加右上 杨辉三角可以通过递推公式计算&#xff1a;C(n, k) C(n-1, k-1) C(n-1, k)&#xff0c;其中 C(n, k) 表…

掌控安全CTF-2024年8月擂台赛-ez_misc

题解&#xff1a; 题目给了一个流量包和一个加密的zip文件&#xff0c;我们首先打开流量包&#xff0c;很多流量&#xff0c;查看一下http协议&#xff0c;发现是个sql靶场&#xff0c;找到关键字样flag&#xff0c;得到一串字符&#xff1a; LJWXQ2C2GN2DAYKHNR5FQMTMPJMDER…

STM32F103C8----GPIO(跟着江科大学STM32)

一&#xff0c;GPIO简介 GPIO&#xff08;General Purpose Input Output&#xff09;通用输入输出口 可配置为8种输入输出模式 引脚电平&#xff1a;0V~3.3V&#xff08;0V&#xff09;&#xff0c;部分引脚可容忍5V 输出模式下可控制端口输出高低电平&#xff0c;用以驱动…

【机器学习-随记】使用 Slack 和 Facebook Messenger 的消息机器人实现虚拟客服人员

使用 Slack 和 Facebook Messenger 的消息机器人实现虚拟客服人员 1. 平台选择与集成 2. 消息机器人开发 3. 自然语言处理 (NLP) 4. 虚拟助手功能实现 5. 语音助手集成 6. 安全与用户隐私 7. 测试与部署 &#x1f388;边走、边悟&#x1f388;迟早会好 实现一个虚拟客…

基于精益六西格玛管理方法进行生产线综合改善

生产线精益六西格玛改善是一个系统工程&#xff0c;只有对其进行系统的策划与组织&#xff0c;才能收到良好的改善效果。一般来说&#xff0c;需要成立一个专门的精益六西格玛推进组织&#xff0c;由其完成一系列的组织、准备工作。具体如下&#xff1a; &#xff08;1&#xf…

王立铭脑科学50讲后续1,自己从课程中提起自己所需的知识,安放到自己的知识体系中。

王立铭脑科学50讲后续1&#xff0c;自己从课程中提起自己所需的知识&#xff0c;安放到自己的知识体系中。 建立第一版——对人类智慧的框架&#xff0c;后期的所有相关知识都安装在这个框架里&#xff0c;不断修正这个框架。 最底层&#xff1a;感知输入系统和动作输出系统&a…

高效过滤器检漏过程中上游浓度过低过高什么原因?

洁净区高效过滤器检漏是确保洁净环境正常运行的重要环节&#xff0c;但是很多企业检测人员&#xff0c;在进行高效过滤器检漏过程中&#xff0c;经常会遇到一些突发问题无法解决&#xff0c;今天中邦兴业技术工程师团队给大家汇总了一些高效过滤器检漏过程中常见问题&#xff0…

【C++】STL学习——vector模拟实现

目录 vector介绍vector函数接口总览结构介绍默认成员函数构造函数1构造函数2构造函数3经典的深浅拷贝拷贝构造赋值重载析构函数 迭代器begin和end 容量相关函数sizecapacityemptyreserveresize 访问operator[] 修改相关函数insertpush_backerasepop_backclearswap 迭代器失效问…

DataGridView用法合集【精品】

目录 1.当前的单元格属性取得、变更 2.DataGridView编辑属性 3.DataGridView最下面一列新追加行非表示 4.判断当前选中行是否为新追加的行 5. DataGridView删除行可否设定 6. DataGridView行列不表示和删除 7. DataGridView行列宽度高度设置为不能编辑 8. DataGridView行…

62-java线程池的执行过程

Java线程池的执行过程主要包括以下几个步骤&#xff1a; 创建线程池&#xff1a;使用ThreadPoolExecutor类创建线程池&#xff0c;并设置核心线程数、最大线程数、队列容量、保持存活时间等参数。 提交任务&#xff1a;将任务&#xff08;通常实现Runnable或Callable接口&…

黑神话:悟空-配置推荐

显卡推荐&#xff08;按类别整理&#xff09; 1. GTX 10系列、GTX 16系列&#xff1a; 如果希望体验光线追踪&#xff0c;建议根据预算升级到RTX 40系列显卡。对于1080p分辨率&#xff0c;至少需要RTX 4060才能流畅运行。 2. RTX 20系列&#xff1a; RTX 2060、RTX 2070&#…

基于Transformer架构训练LLM大语言模型:Transformer架构工作原理

视频讲解&#xff1a;Transformer架构的工作原理讲解_哔哩哔哩_bilibili 一 Transformer架构总体架构 1 总体架构图 总体架构说明&#xff1a; 输入层 词嵌入&#xff08;Word Embeddings&#xff09;: 输入文本中的每个词都被映射到一个高维空间中的向量&#xff0c;这些向…

最新Python安装+PyCharm安装激活和使用教程(pycharm激活)

PyCharm激活 激活码&#xff1a; EUWT4EE9X2-eyJsaWNlbnNlSWQiOiJFVVdUNEVFOVgyIiwibGljZW5zZWVOYW1lIjoic2lnbnVwIHNjb290ZXIiLCJhc3NpZ25lZU5hbWUiOiIiLCJhc3NpZ25lZUVtYWlsIjoiIiwibGljZW5zZVJlc3RyaWN0aW9uIjoiIiwiY2hlY2tDb25jdXJyZW50VXNlIjpmYWxzZSwicHJvZHVjdHMiOlt7…

【mac】brew 更新

【mac】brew 更新 更新 Homebrew 要获取最新的包的列表&#xff0c;首先得更新 Homebrew 自己。这可以用 brew update 办到。 brew update完后会显示可以更新的包列表&#xff0c;其中打钩的是已经安装的包。输出类似下面这样&#xff1a; > Updating Homebrew... Updat…

【STM32+HAL库】---- 通用定时器PWM输出实现呼吸灯

硬件开发板&#xff1a;STM32G0B1RET6 软件平台&#xff1a;cubemaxkeilVScode1 新建cubemax工程 1.1 配置系统时钟RCC 1.2 配置定时器 找到LED所对应的引脚PA5&#xff0c;选择TIM2_CH1模式 在TIM2中&#xff0c;时钟源选择内部时钟Internal Clock&#xff0c;通道1选择PWM…

内置消息支持

内置消息支持 MATLAB 支持大量的 ROS 消息类型。本主题介绍了 MATLAB 如何通过描述消息结构、ROS 消息的限制以及支持的 ROS 数据类型来处理 ROS 消息。有关内置消息类型的完整列表&#xff0c;请参见本文末尾。 有关 ROS 2 消息的信息&#xff0c;请参见“使用基础 ROS 2 消…

uniapp布局

一. 如何让元素吸顶? position: sticky;top: 0; 注意&#xff1a;暂时仅支持作为list-view、sticky-section的子节点, sticky-header不支持css样式&#xff01;当一个容器视图设置多个sticky-header时&#xff0c;后一个sticky-header会停靠在前一个sticky-header的末尾处。

chrome 插件开发入门

1. 介绍 Chrome 插件可用于在谷歌浏览器上控制当前页面的一些操作&#xff0c;可自主控制网页&#xff0c;提升效率。 平常我们可在谷歌应用商店中下载谷歌插件来增强浏览器功能&#xff0c;作为开发者&#xff0c;我们也可以自己开发一个浏览器插件来配合我们的日常学习工作…