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

MongoDB多分组求和聚合查询转Spring MongoTemplate实现求助

解决方案:将MongoDB聚合查询转换为Spring MongoTemplate实现

原查询逻辑回顾

你的聚合查询核心是:关联集合B后,按集合A的_id分组,对比集合A中notes数组长度与关联的集合B文档数量,筛选不匹配的结果并按更新时间排序。

分步实现Spring MongoTemplate代码

1. 定义结果接收DTO(可选但推荐)

创建DTO类接收聚合结果,避免使用松散的Map结构:

import org.bson.types.ObjectId;
import java.util.Date;

public class CollectionAMismatchResult {
    private ObjectId _id;
    private int fromB;
    private int numberOfNotes;
    private Date updatedAt;

    // 构造器、getter、setter
    public CollectionAMismatchResult(ObjectId _id, int fromB, int numberOfNotes, Date updatedAt) {
        this._id = _id;
        this.fromB = fromB;
        this.numberOfNotes = numberOfNotes;
        this.updatedAt = updatedAt;
    }

    // 省略getter和setter方法
}

2. 构建完整聚合操作链

import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;
import java.util.List;

// 注入MongoTemplate实例
private final MongoTemplate mongoTemplate;

public List<CollectionAMismatchResult> findMismatchedDocuments() {
    // 1. 实现$lookup:关联collectionB
    LookupOperation lookupOperation = Aggregation.lookup(
            "collectionB",       // 目标集合名
            "_id",               // 集合A的关联字段
            "idNotes",           // 集合B的关联字段
            "documentB"          // 关联结果的别名
    );

    // 2. 实现$group:按_id分组,计算两个长度值并保留updatedAt
    GroupOperation groupOperation = Aggregation.group("_id")
            // 计算fromB:documentB数组长度,非数组则取0
            .sum((context) -> new org.bson.Document("$cond",
                    new org.bson.Document("if", new org.bson.Document("$isArray", "$documentB"))
                            .append("then", new org.bson.Document("$size", "$documentB"))
                            .append("else", 0)
            )).as("fromB")
            // 计算numberOfNotes:notes数组长度,非数组则取0
            .sum((context) -> new org.bson.Document("$cond",
                    new org.bson.Document("if", new org.bson.Document("$isArray", "$notes"))
                            .append("then", new org.bson.Document("$size", "$notes"))
                            .append("else", 0)
            )).as("numberOfNotes")
            // 保留分组内第一个updatedAt值
            .first("updatedAt").as("updatedAt");

    // 3. 实现$match:筛选长度不匹配的文档
    MatchOperation matchOperation = Aggregation.match(
            Criteria.where("").expr(
                    ComparisonOperators.Ne.valueOf("fromB").notEqualToValue("numberOfNotes")
            )
    );

    // 4. 实现$sort:按updatedAt降序排序
    SortOperation sortOperation = Aggregation.sort(Sort.Direction.DESC, "updatedAt");

    // 组装聚合管道
    Aggregation aggregation = Aggregation.newAggregation(
            lookupOperation,
            groupOperation,
            matchOperation,
            sortOperation
    );

    // 执行查询并转换为DTO列表
    AggregationResults<CollectionAMismatchResult> results = mongoTemplate.aggregate(
            aggregation,
            "collectionA",
            CollectionAMismatchResult.class
    );

    return results.getMappedResults();
}

关键细节说明

  • GroupOperation复杂表达式:通过Lambda形式的AggregationExpression手动构建MongoDB的$cond逻辑,解决Spring Data API无法直接覆盖复杂条件的问题。
  • MatchOperation字段对比:使用Criteria.where("").expr()实现MongoDB的$expr语法,支持对聚合计算后的字段进行对比。
  • 类型安全处理:用DTO接收结果比直接使用Map更易维护,Spring会自动完成字段映射。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 03:05:16