在使用springdata 构建mongodb聚合分页查询时,由于擅自创建PageImpl而引发的分页血案。。
现象:后台得到的总记录数不正常,数据库查询19条,接口查询返回29条
事发现场:
Aggregation aggregation = Aggregation.newAggregation(
Aggregation.sort(sort), //排序
Aggregation.lookup("cps_config", "configId", "id", "configModel"),//关联表
Aggregation.match(criteria),//查询条件
Aggregation.skip(skip), //跳过文档数量
Aggregation.limit(pageSize)//每页显示数量
);
AggregationResults queryResult = mongoTemplate
.aggregate(aggregation, "cps_config", CpsConfigDetail.class);
AggregationResults countResult = mongoTemplate
.aggregate(countAggregation, "cps_config", CpsConfigDetail.class);
Page pager;
if(!CollectionUtils.isEmpty(queryResult.getMappedResults())){
//在这里手动构建 spring data pageImpl对象
pager = new PageImpl<>
(queryResult.getMappedResults(),pageBale,countResult.getMappedResults().size());
。。。。。
}
勘查过程:
接口返回的总记录数与数据库不一致,于是debug PageImpl 构造方法,发现 构造方法中 计算总记录数采用了Pageable对象的方法
public PageImpl(List content, Pageable pageable, long total) {
super(content, pageable);
// 如果pageable的offset加上 pageSize 大于数据库总记录数,则total= pageable.offset +
// content.size(),否则直接返回total
this.total = pageable.toOptional().filter(it -> !content.isEmpty())
.filter(it -> it.getOffset() + it.getPageSize() > total)
.map(it -> it.getOffset() + content.size())
.orElse(total);
}
于是追查源码找到getOffset实现 ----》
public long getOffset() {
return page * size;
}
最终发现,是由于前段传递page参数为1,而mongodb 分页从0开始,offset的计算应该为 page -1 * size 才对。
最终统一初始化Pageable,解决问题!
总结:1.spring data 分页查询的pageable对象一般由 spring data 接口实现内部调用
2.在复杂查询时并未构建pageable对象作为查询参数,封装分页结果时使用了 springdata 的 Page,要注意 offset 的计算是否正确。
3.你能想象玩意我弄了一下午???吐血