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

如何用Spring Data MongoDB实现聚合投影中$substr的复杂表达式

Spring Data MongoDB 聚合查询完整实现

一、规范实现(类型安全操作符)

替代原生表达式写法,用Spring Data提供的StringOperators和ArithmeticOperators完成字段投影,避免硬编码MongoDB语法:

import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.ArithmeticOperators;
import org.springframework.data.mongodb.core.aggregation.GroupOperation;
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation;
import org.springframework.data.mongodb.core.MongoTemplate;

// 聚合结果映射类
class PartnerOfficeStats {
    private String partnerid;
    private String market;
    private String office;
    private Long clickCount;

    // 生成Getter、Setter方法
}

public class AggregationService {
    private final MongoTemplate mongoTemplate;

    // 通过构造注入MongoTemplate
    public AggregationService(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

    public AggregationResults<PartnerOfficeStats> getPartnerClickStats() {
        // 构建market字段:截取pseudocitycode前3位并转大写
        StringOperators.ToUpper marketExpr = StringOperators.valueOf("pseudocitycode")
                .substring(0, 3)
                .toUpper();

        // 构建office字段:计算起始位置(字符串长度-2),截取后2位并转大写
        ArithmeticOperators.Subtract startPos = ArithmeticOperators
                .valueOf(StringOperators.valueOf("pseudocitycode").lengthCP())
                .subtract(2);
        StringOperators.ToUpper officeExpr = StringOperators.valueOf("pseudocitycode")
                .substring(startPos, 2)
                .toUpper();

        // 投影阶段
        ProjectionOperation projection = Aggregation.project("partnerid")
                .and(marketExpr).as("market")
                .and(officeExpr).as("office");

        // 分组阶段:按partnerid、market、office分组,统计点击数
        GroupOperation group = Aggregation.group("partnerid", "market", "office")
                .count().as("clickCount");

        // 构建聚合管道并执行
        Aggregation aggregation = Aggregation.newAggregation(projection, group);
        return mongoTemplate.aggregate(aggregation, "collection", PartnerOfficeStats.class);
    }
}

二、兼容原有表达式写法(快速适配)

如果想保留你原来的andExpression写法,只需要补充完整的聚合流程即可:

import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.GroupOperation;
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation;
import org.springframework.data.mongodb.core.MongoTemplate;

public class AggregationService {
    private final MongoTemplate mongoTemplate;

    public AggregationService(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

    public AggregationResults<PartnerOfficeStats> getPartnerClickStats() {
        StringOperators.Substr market = StringOperators.valueOf("pseudocitycode").substring(0, 3);
        
        ProjectionOperation projectionOperation = Aggregation.project("partnerid")
                .and(StringOperators.valueOf(market).toUpper()).as("market")
                .andExpression("{$toUpper:[{$substr:['$pseudocitycode',{$subtract:[{$strLenCP:'$pseudocitycode'},2]},2]}]}").as("office");

        GroupOperation group = Aggregation.group("partnerid", "market", "office")
                .count().as("clickCount");

        Aggregation aggregation = Aggregation.newAggregation(projectionOperation, group);
        return mongoTemplate.aggregate(aggregation, "collection", PartnerOfficeStats.class);
    }
}

说明

  • 两种写法功能完全等价,推荐第一种类型安全的操作符链式写法,便于维护和避免语法错误。
  • PartnerOfficeStats类用于映射聚合结果,字段名需和投影、分组后的字段名对应。
  • 替换代码中的"collection"为你的实际MongoDB集合名称。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 07:10:35