MongoTemplate对LocalDateTime字段排序失效及分页功能异常问题排查
核心错误排查
你当前的代码存在两个优先级最高的基础错误,是所有异常的根源:
- 构造的
Criteria条件列表没有添加到Query对象中,所有查询实际执行的是全表无条件查询 - 分页总条数计算逻辑错误,直接将当前页的结果条数作为全量符合条件的总记录数,导致Page元数据完全错误
各问题解决方案
1. 排序失效、分页重复问题
- 先修正字段拼写错误:你实体类中声明的
LocaleDateTime属于拼写错误,正确的JDK时间类是java.time.LocalDateTime,字段类型拼写错误会导致Mongo无法识别该字段,排序自然失效 - 补充稳定排序规则:Mongo单字段排序为不稳定排序,若多条记录
createdAt值相同,每次查询返回顺序可能不一致,导致分页重复。需要追加唯一字段作为第二排序条件:Sort sort = Sort.by(Sort.Direction.DESC, "createdAt") .and(Sort.by(Sort.Direction.DESC, "id")); Pageable pageable = PageRequest.of(skip == 0 ? skip : skip/first, first, sort); - 将Criteria条件添加到Query对象中:
if (!criteria.isEmpty()) { query.addCriteria(new Criteria().andOperator(criteria.toArray(new Criteria[0]))); }
2. 分页元数据错误问题
你之前使用() -> (long)users.size()作为总条数查询逻辑,返回的始终是当前页的结果条数,需要改为调用MongoTemplate的count方法查询全量符合条件的记录数:
return PageableExecutionUtils.getPage(users, page, () -> mongoTemplate.count(Query.of(query).limit(-1).skip(-1), UserDocument.class));
这里复制原Query并清空limit、skip参数,是为了复用查询条件,保证count结果和分页查询条件完全一致。
3. 直接返回Slice类型
可以直接构造Slice返回,无需经过Page转换,Slice不需要查询全量总条数,性能更高,实现逻辑如下:
public Slice<UserDocument> findUsersByPropertiesSlice(String name, String email, Pageable page) { final Query query = new Query().with(page); final List<Criteria> criteria = new ArrayList<>(); // 省略Criteria构造逻辑,同上 if (!criteria.isEmpty()) { query.addCriteria(new Criteria().andOperator(criteria.toArray(new Criteria[0]))); } // 多查1条记录判断是否存在下一页 query.limit(page.getPageSize() + 1); List<UserDocument> users = mongoTemplate.find(query, UserDocument.class); boolean hasNext = users.size() > page.getPageSize(); if (hasNext) { users = users.subList(0, page.getPageSize()); } return new SliceImpl<>(users, page, hasNext); }
修正后完整Repository实现
@Repository public class UserCustom implements UserRepository { @Autowired MongoTemplate mongoTemplate; public Page<UserDocument> findUsersByProperties(String name, String email, Pageable page) { final Query query = new Query().with(page); final List<Criteria> criteria = new ArrayList<>(); if (name != null && !name.isEmpty()) { criteria.add(Criteria.where("name").is(name)); } if (email != null && !email.isEmpty()) { criteria.add(Criteria.where("email").is(email)); } // 补充添加Criteria到Query的逻辑 if (!criteria.isEmpty()) { query.addCriteria(new Criteria().andOperator(criteria.toArray(new Criteria[0]))); } List<UserDocument> users = mongoTemplate.find(query, UserDocument.class); return PageableExecutionUtils.getPage(users, page, // 修正总条数查询逻辑 () -> mongoTemplate.count(Query.of(query).limit(-1).skip(-1), UserDocument.class)); } }
内容的提问来源于stack exchange,提问作者Barbi
相关产品推荐
相关产品推荐

