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

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

  • SQL查询结果示例:
  • 多种查询结果示例:

原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();
        // 按商家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类
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语句

yaml 复制代码
logging:
  level:
    org.springframework.data.mongodb.core.MongoTemplate: DEBUG
相关推荐
小汤猿人类2 分钟前
open Feign 连接池(性能提升)
数据库
新手小袁_J19 分钟前
JDK11下载安装和配置超详细过程
java·spring cloud·jdk·maven·mybatis·jdk11
呆呆小雅20 分钟前
C#关键字volatile
java·redis·c#
Monly2121 分钟前
Java(若依):修改Tomcat的版本
java·开发语言·tomcat
阳冬园23 分钟前
mysql数据库 主从同步
数据库·主从同步
Ttang2323 分钟前
Tomcat原理(6)——tomcat完整实现
java·tomcat
钱多多_qdd34 分钟前
spring cache源码解析(四)——从@EnableCaching开始来阅读源码
java·spring boot·spring
waicsdn_haha36 分钟前
Java/JDK下载、安装及环境配置超详细教程【Windows10、macOS和Linux图文详解】
java·运维·服务器·开发语言·windows·后端·jdk
Q_19284999061 小时前
基于Spring Boot的摄影器材租赁回收系统
java·spring boot·后端
Code_流苏1 小时前
VSCode搭建Java开发环境 2024保姆级安装教程(Java环境搭建+VSCode安装+运行测试+背景图设置)
java·ide·vscode·搭建·java开发环境