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

如何用Spring Data MongoDB Criteria查询统计DELIVRD状态数据条数

问题:Spring Data MongoDB 实现聚合统计DATA_LIST中DELIVRD状态的数量

现有MongoDB集合结构

{ 
  "_id" : "7959305563", 
  "_class" : "com.loylty.messagingEngine.entities.message.GroupIdDeliveryStatusReport", 
  "DATA_LIST" : [ 
    { "_id" : "7959305562-1", "mobile" : "9566337867", "status" : "DELIVRD", "senttime" : "2018-01-09 14:19:42", "dlrtime" : "2018-01-09 14:57:06", "custom" : "9566337867" }, 
    { "_id" : "7959305562-2", "mobile" : "9566337867", "status" : "DELIVRD", "senttime" : "2018-01-09 14:19:42", "dlrtime" : "2018-01-09 14:57:05", "custom" : "9566337867" }, 
    { "_id" : "7959305562-3", "mobile" : "9566337867", "status" : "DELIVRD", "senttime" : "2018-01-09 14:19:42", "dlrtime" : "2018-01-09 14:57:04", "custom" : "9566337867" } 
  ] 
}

对应的Java实体类

@Document(collection = "GROUP_ID_DELIVERY_STATUS")
public class GroupIdDeliveryStatusReport {
    @Id
    @Field("GROUP_ID")
    private String groupId;
    @Field("DATA_LIST")
    private List<SolInfiniGroupIdData> data;

    public String getGroupId() { return groupId; }
    public void setGroupId(String groupId) { this.groupId = groupId; }
    public List<SolInfiniGroupIdData> getData() { return data; }
    public void setData(List<SolInfiniGroupIdData> data) { this.data = data; }
}

需求

统计集合中DATA_LIST数组里status为DELIVRD的元素总数量(示例预期结果为3)。

已验证的Mongo Shell聚合查询

db.getCollection('GROUP_ID_DELIVERY_STATUS').aggregate(
    { "$unwind" : "$DATA_LIST"},
    { "$match" : {"DATA_LIST.status": "DELIVRD" } },
    { $group: { _id: null, count: { $sum: 1 } } }
)

当前Spring Data MongoDB代码问题

你尝试转换为Spring Data查询,但未正确实现高效的统计逻辑,当前代码如下:

package com.loylty.messagingEngine.service.Impl;

import com.loylty.messagingEngine.service.GroupIdDeliveryStatusReportService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;

@Service
public class GroupIdDeliveryStatusReportServiceImpl implements GroupIdDeliveryStatusReportService {
    @Autowired
    private MongoOperations mongoOperations;

    @Override
    public void getDeliveryCount() {
        Aggregation aggregation = newAggregation(
            //match(Criteria.where("_id").in("7959305563")), //Use this if you want to do this operation for particular document only
            unwind("DATA_LIST"),
            match(Criteria.where("DATA_LIST.status").is("DELIVRD")),
            project("DATA_LIST._id")
        );
        AggregationResults<String> groupResults = mongoOperations.aggregate(aggregation, "GroupIdDeliveryStatusReport", String.class);
        int count = groupResults.getMappedResults().size();
    }
}

正确的Spring Data MongoDB实现方案

你当前用project后统计结果数量的方式虽然能得到结果,但性能较差(会把所有匹配的文档传输到应用层再统计),应该直接在聚合阶段完成统计,和Mongo Shell的逻辑保持一致。

步骤1:创建统计结果的DTO(可选,也可用Map接收)

先创建一个简单类来接收聚合后的统计结果:

public class DeliveryCountResult {
    private Long count;

    public DeliveryCountResult() {}

    public DeliveryCountResult(Long count) {
        this.count = count;
    }

    public Long getCount() {
        return count;
    }

    public void setCount(Long count) {
        this.count = count;
    }
}

步骤2:修改聚合逻辑

把project替换为group操作,直接在数据库端计算总数:

@Override
public Long getDeliveryCount() {
    Aggregation aggregation = newAggregation(
        // 如果需要针对特定GROUP_ID查询,解开下面的注释
        // match(Criteria.where("_id").is("7959305563")),
        unwind("DATA_LIST"),
        match(Criteria.where("DATA_LIST.status").is("DELIVRD")),
        group().count().as("count") // 对应Mongo Shell中的$group: {_id: null, count: {$sum:1}}
    );

    // 用实体类Class代替硬编码集合名称,和@Document注解保持一致更易维护
    AggregationResults<DeliveryCountResult> results = mongoOperations.aggregate(
        aggregation, 
        GroupIdDeliveryStatusReport.class, 
        DeliveryCountResult.class
    );

    // 获取统计结果,无匹配项时返回0
    return results.getUniqueMappedResult() != null ? results.getUniqueMappedResult().getCount() : 0L;
}

关键说明

  • group().count().as("count") 完全等价于Mongo Shell中的{ $group: { _id: null, count: { $sum: 1 } } },直接在数据库端完成统计,避免大量数据传输。
  • 使用getUniqueMappedResult()而非getMappedResults(),因为聚合后只会返回一个结果文档。
  • 若不想额外创建DTO,也可以用Map接收结果:
AggregationResults<Map> results = mongoOperations.aggregate(
    aggregation, 
    GroupIdDeliveryStatusReport.class, 
    Map.class
);
Map<String, Object> resultMap = results.getUniqueMappedResult();
Long count = resultMap != null ? (Long) resultMap.get("count") : 0L;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:25:10