You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Data MongoDB分组投影实现支付类型金额聚合求助

问题描述

现有3条MongoDB示例记录:

{
  "_id" : "0cc5c468-2105-11ee-ad68-15d467e62by4d",
  "storeId" : "3070",
  "paymentType" : "cash",
  "total" : {"$numberDecimal": "100"}
},
{
  "_id" : "1111111-2105-11ee-ad68-15d467e62by4d",
  "storeId" : "3070",
  "paymentType" : "cash",
  "total" : {"$numberDecimal": "100"}
},
{
  "_id" : "0cc5c468-2105-11ee-ad68-15d467e62by4d",
  "storeId" : "3070",
  "paymentType" : "creditCard",
  "total" : {"$numberDecimal": "50"}
}

期望通过分组投影得到如下格式的输出(最后一列可忽略):

StoreId | Cash Payment | Card Payment | Total Amount Cash + Card
3070        200               50                250

当前编写的GroupOperation会生成现金支付和信用卡支付两条独立记录,不符合预期:

GroupOperation groupingLogic() {
        return group("storeId", "paymentType")
                .first("storeId").as("storeId")
                .first("paymentType").as("paymentType")
                .sum(TOTAL).as(TOTAL);
    }

需要正确的Java MongoDB实现代码。


解决方案

正确的做法是仅按storeId分组,使用条件求和分别计算不同支付类型的总额,同时可额外计算总和。以下是实现代码:

import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.GroupOperation;
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
import static org.springframework.data.mongodb.core.aggregation.ConditionalOperators.when;

public class StorePaymentAggregation {

    private static final String STORE_ID = "storeId";
    private static final String PAYMENT_TYPE = "paymentType";
    private static final String TOTAL = "total";
    private static final String CASH_PAYMENT = "Cash Payment";
    private static final String CARD_PAYMENT = "Card Payment";
    private static final String TOTAL_AMOUNT = "Total Amount Cash + Card";

    public GroupOperation groupingLogic() {
        return group(STORE_ID)
                // 统计现金支付总额:仅累加paymentType为cash的total值
                .sum(when(PAYMENT_TYPE).is("cash").then(TOTAL).otherwise(0)).as(CASH_PAYMENT)
                // 统计信用卡支付总额:仅累加paymentType为creditCard的total值
                .sum(when(PAYMENT_TYPE).is("creditCard").then(TOTAL).otherwise(0)).as(CARD_PAYMENT)
                // 计算所有支付类型的总额(可选)
                .sum(TOTAL).as(TOTAL_AMOUNT);
    }

    // 可选:投影操作,调整输出字段顺序与格式
    public ProjectionOperation projectionLogic() {
        return project(STORE_ID, CASH_PAYMENT, CARD_PAYMENT, TOTAL_AMOUNT)
                .and(STORE_ID).previousOperation();
    }

    // 聚合执行示例
    public void executeAggregation() {
        Aggregation aggregation = newAggregation(
                groupingLogic(),
                projectionLogic() // 按需添加
        );
        // 后续通过mongoTemplate执行聚合,示例:
        // mongoTemplate.aggregate(aggregation, "your-collection-name", PaymentSummary.class);
    }
}

// 对应结果的实体类示例
class PaymentSummary {
    private String storeId;
    private Number cashPayment;
    private Number cardPayment;
    private Number totalAmount;

    // Getter、Setter方法
}

代码说明

  1. 分组维度调整:仅以storeId作为分组键,确保每个门店只生成一条汇总记录。
  2. 条件求和逻辑:通过ConditionalOperators.when判断支付类型,对符合条件的total字段累加,不符合的则加0,实现不同支付类型的单独统计。
  3. 可选总和计算:直接使用sum(TOTAL)累加所有支付记录的总额,得到合计值。
  4. 投影操作:可选用于规范输出字段的顺序,让结果更贴合期望格式。

内容的提问来源于stack exchange,提问作者jarvo69

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 20:34:59