如何在Spring Data MongoDB中结合Skip、Limit使用Distinct
Hey there! 我之前刚好踩过这个坑,来给你详细说说怎么解决~
先明确版本支持情况
首先,Spring Data MongoDB的旧版本(比如2.x及以下)确实没有直接提供先去重再分页(Distinct + Skip + Limit)的API,因为MongoDB原生的distinct命令本身就不支持分页操作。而在Spring Data MongoDB 3.x及以上的版本里,虽然MongoTemplate有带Query参数的distinct重载方法,但要注意:这个Query里的skip和limit是作用在原始文档上的,也就是先跳过N条原始数据、取M条,再对这M条做去重——这和你要的「先对全量数据去重,再对去重后的结果分页」完全不是一回事,所以这个方法满足不了需求。
正确方案:用聚合框架实现
要实现「先去重,再对去重结果做Skip+Limit」,必须借助MongoDB的聚合框架,Spring Data MongoDB对此有很好的支持。核心思路是用$group实现去重,再依次加上$skip和$limit,最后用$project整理返回字段。
代码示例(Java)
假设你的集合名为products,要对category字段去重,然后跳过前10个去重结果,取20条:
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.bson.Document; import java.util.List; import java.util.stream.Collectors; // 注入MongoTemplate private final MongoTemplate mongoTemplate; public List<String> getDistinctCategoriesWithPagination(long skip, long limit) { // 构建聚合管道 Aggregation aggregation = Aggregation.newAggregation( // 第一步:按category分组,实现去重(_id就是去重后的category值) Aggregation.group("category"), // 第二步:跳过指定数量的去重结果 Aggregation.skip(skip), // 第三步:限制返回的去重结果数量 Aggregation.limit(limit), // 第四步:把_id字段重命名为category,方便后续处理 Aggregation.project().and("_id").as("category") ); // 执行聚合查询 AggregationResults<Document> results = mongoTemplate.aggregate( aggregation, "products", // 你的集合名称 Document.class ); // 把结果转换为字符串列表 return results.getMappedResults() .stream() .map(doc -> doc.getString("category")) .collect(Collectors.toList()); }
关键点说明
$group去重:通过按目标字段分组,_id会自动成为去重后的唯一值,这是聚合实现去重的标准方式。- 分页顺序:必须先做
$group去重,再执行$skip和$limit——如果顺序反过来,就会变成先分页原始数据再去重,结果不符合预期。 - 多字段组合去重:如果需要对多个字段组合去重,只需要把
group("category")改成group("field1", "field2"),然后在$project里把_id下的子字段提取出来即可。
内容的提问来源于stack exchange,提问作者lokesh kotha
相关产品推荐
相关产品推荐

