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
  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哒不溜-w

别给我打手续费太贵

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值