如何用MongoTemplate实现带分页排序的多集合统计查询
可以通过MongoTemplate实现该需求
完全可以通过MongoTemplate结合MongoDB的聚合框架来实现你需要的查询,包括用户信息关联、统计计数、分页和排序功能。以下是具体实现方案:
核心思路:使用MongoDB聚合管道
我们需要构建一个聚合管道,依次完成关联Catalog集合、统计Catalog数量、关联Item集合、统计Item数量、结果塑形、排序和分页这几个步骤。
聚合管道步骤拆解
- 关联Catalog集合:通过用户ID将User与所属的Catalog关联,得到用户的所有Catalog列表。
- 统计Catalog数量:计算关联得到的Catalog列表的长度,得到
countOfCatalogs。 - 关联Item集合:同样通过用户ID关联用户所属的Item列表(若需通过Catalog关联Item,可调整关联条件)。
- 统计Item数量:计算Item列表的长度,得到
countOfItems。 - 结果塑形:将原始用户字段封装为
user对象,保留计数字段,形成Response结构。 - 排序:根据
countOfCatalogs或countOfItems字段进行排序。 - 分页:通过
skip和limit实现分页逻辑。
Java代码实现
假设你的MongoDB集合名称分别为user、catalog、item(若实体类使用@Document指定了集合名,请对应调整):
1. 构建聚合阶段
import org.springframework.data.mongodb.core.aggregation.*; import org.springframework.data.domain.Sort; import org.springframework.data.mongodb.core.MongoTemplate; import java.util.Arrays; import java.util.List; // 1. 关联Catalog并过滤有效记录(可选:只统计exist=true的Catalog) LookupOperation lookupCatalogs = LookupOperation.newLookup() .from("catalog") .localField("id") .foreignField("userId") .pipeline(Arrays.asList(Aggregation.match(Criteria.where("exist").is(true)))) .as("catalogs"); // 2. 计算Catalog数量 AddFieldsOperation addCatalogCount = Aggregation.addFields() .addFieldWithValue("countOfCatalogs", AggregationExpression.from(MongoExpression.create("{ $size: \"$catalogs\" }"))) .build(); // 3. 关联Item(若需通过Catalog关联Item,可将localField改为"catalogs.id") LookupOperation lookupItems = LookupOperation.newLookup() .from("item") .localField("id") .foreignField("userId") .as("items"); // 4. 计算Item数量 AddFieldsOperation addItemCount = Aggregation.addFields() .addFieldWithValue("countOfItems", AggregationExpression.from(MongoExpression.create("{ $size: \"$items\" }"))) .build(); // 5. 塑形为Response结构 ProjectOperation project = Aggregation.project() .and(Aggregation.fields() .and("id").as("user.id") .and("catalogId").as("user.catalogId") .and("name").as("user.name") .and("info").as("user.info")) .and("countOfCatalogs").as("countOfCatalogs") .and("countOfItems").as("countOfItems") .andExclude("_id"); // 6. 排序(示例:按countOfCatalogs降序,可根据需求动态调整) SortOperation sort = Aggregation.sort(Sort.Direction.DESC, "countOfCatalogs"); // 7. 分页(示例:第1页,每页10条) int pageNum = 1; int pageSize = 10; SkipOperation skip = Aggregation.skip((long) (pageNum - 1) * pageSize); LimitOperation limit = Aggregation.limit(pageSize);
2. 组装并执行聚合查询
// 组装聚合管道 Aggregation aggregation = Aggregation.newAggregation( lookupCatalogs, addCatalogCount, lookupItems, addItemCount, project, sort, skip, limit ); // 执行查询并映射为Response列表 List<Response> responseList = mongoTemplate.aggregate(aggregation, "user", Response.class).getMappedResults();
关键注意事项
- 集合名称匹配:确保
from()方法中的集合名称与MongoDB中实际集合名一致(实体类若用@Document(collection = "xxx")注解,需对应调整)。 - 索引优化:为
catalog.userId、item.userId(或item.catalogId)创建索引,大幅提升关联查询的性能。 - 动态排序分页:可根据前端传入的排序字段、方向和分页参数,动态构建
SortOperation、SkipOperation和LimitOperation。 - 空值处理:若用户无对应的Catalog或Item,
$size会返回0,符合统计需求。
内容的提问来源于stack exchange,提问作者roditoo
相关产品推荐
相关产品推荐

