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

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语句大差不差
(懒得替换类名,大家看到陌生的类就是自己建的)

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();
        // 按商家id
        String 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类
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.kler.cn/a/290219.html

相关文章:

  • 大语言模型:解锁自然语言处理的无限可能
  • 前端开发中常用的包管理器(npm、yarn、pnpm、bower、parcel)
  • 区块链技术在慈善捐赠中的应用
  • 【C++】C++11特性(上)
  • 【真题笔记】21年系统架构设计师案例理论点总结
  • 重构代码之内联临时变量
  • OpenCV绘图函数(11)计算文本字符串在特定字体、尺寸和厚度下的大小的函数getTextSize()的使用
  • 模型从 HuggingFace 转存到 ModelScope
  • 【ubuntu使用笔记】Ubuntu Desktop 访问SMB共享文件夹
  • Spring声明式事务使用详情(知识点+案例)
  • 【Java】封装
  • 《Zookeeper 的监听机制及原理解析》
  • 后台使用Motionbuilder
  • 聚类算法-Kmeans聚类
  • 【60天备战软考高级系统架构设计师——第八天:设计模式概述】
  • Spring Boot项目中结合MyBatis详细使用
  • “智能化自动化” 架构之4:中间建模脑的软件设计三大原则-依赖倒置控制反转和依赖注入
  • 在react中利用three.js 渲染模型 让鼠标拖拽是模型转动
  • redhat7.9安装zsh以及常用插件
  • 具有平面规则性的单目视觉惯性里程计
  • 反射API与AOP在微服务治理中的实践与思考
  • 飞利浦开放式耳机怎么样?南卡、飞利浦、QCY耳机真实测评
  • 【Leetcode 2399 】 检查相同字母间的距离 —— 哈希表
  • git分支的管理
  • Windows 欺骗主机 Burn-In 的自动化工具
  • Mysql-慢SQL的处理以及SQL优化