Spring MongoTemplate如何统计projectCategories的唯一值及出现次数
完全可以通过Spring MongoTemplate实现该需求,核心是借助MongoDB的$objectToArray聚合操作符处理动态键的projectCategories对象,再配合展开、分组统计即可完成。
实现思路
- 第一步:通过
$objectToArray将projectCategories的键值对象转换为[{k: "键", v: "值"}, ...]格式的数组 - 第二步:通过
$unwind展开上述数组,让每个分类值单独对应一条文档 - 第三步:通过
$group按分类值(也就是数组元素的v字段)分组,用$sum统计出现次数 - 可选步骤:通过
$sort按统计次数排序,方便查看结果
代码实现
首先定义结果接收DTO:
import lombok.Data; @Data public class CategoryCountDTO { // 分类名称 private String categoryName; // 出现次数 private Long count; }
然后编写MongoTemplate聚合查询逻辑:
import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.aggregation.Aggregation; import org.springframework.data.mongodb.core.aggregation.AggregationResults; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.List; import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; import static org.springframework.data.mongodb.core.aggregation.ObjectOperators.ObjectToArray; @Component public class ProjectCategoryStatistic { @Resource private MongoTemplate mongoTemplate; public List<CategoryCountDTO> getCategoryCount() { Aggregation aggregation = newAggregation( // 可选:提前过滤没有分类字段的无效文档,提升查询效率 match(Criteria.where("projectCategories").exists(true).ne(null)), // 将projectCategories对象转为数组 project().and(ObjectToArray.valueOf("projectCategories")).as("categoryArr"), // 展开分类数组 unwind("categoryArr"), // 按分类值分组统计次数 group("categoryArr.v").count().as("count"), // 映射字段,适配DTO结构 project() .and("_id").as("categoryName") .and("count").as("count") .exclude("_id"), // 可选:按出现次数倒序排序 sort(Sort.Direction.DESC, "count") ); // 若你有对应集合的实体类,也可将第二个参数替换为实体类.class,不需要手写集合名 AggregationResults<CategoryCountDTO> result = mongoTemplate.aggregate(aggregation, "你的集合名", CategoryCountDTO.class); return result.getMappedResults(); } }
注意事项
- 10万条数据量级下该聚合执行效率很高,常规配置的MongoDB实例单次查询耗时在百毫秒级别
- 如果
projectCategories存在空对象的情况,可在match阶段补充ne(new HashMap<>())过滤空值
内容的提问来源于stack exchange,提问作者MetaCoder
相关产品推荐
相关产品推荐

