Loading... 在使用 MongoDB 的 Spring Data 进行分页和条件查询时,可能会遇到一些常见的坑和问题。本文将结合实际操作总结这些问题,并给出解决方案。 --- #### 代码示例 以下是一个典型的分页与条件查询代码: ```java Pageable pageable = PageRequest.of(page - 1, size, Sort.by("orderNumber").descending()); // 构建查询条件 Query query = new Query(); if (orderNumber != null && !orderNumber.isEmpty()) { query.addCriteria(Criteria.where("orderNumber").is(Long.valueOf(orderNumber))); } if (consignee != null && !consignee.isEmpty()) { query.addCriteria(Criteria.where("consignee").regex(consignee, "i")); } if (beginTime != null) { query.addCriteria(Criteria.where("createdAt").gte(beginTime)); } if (endTime != null) { query.addCriteria(Criteria.where("createdAt").lte(endTime)); } // 总条数(先查询总条数,之后分页后总条数会变) long total = mongoTemplate.count(query, OrderEntity.class); // 查询分页结果 query.with(pageable); List<OrderEntity> orderEntities = mongoTemplate.find(query, OrderEntity.class); ``` 通过这个代码,以下是遇到的问题及解决方案。 --- ### 问题一:分页操作对总条数查询的影响 #### 问题描述 执行分页操作时,如果在查询总条数之前调用了 `query.with(pageable)`,会导致 `count` 查询结果错误。原因是 `with(pageable)` 会修改 `query` 对象,导致分页限制被应用到总条数查询中。 #### 解决方案 在进行总条数查询时,确保 `query` 对象未被 `with(pageable)` 修改。可以按照以下顺序操作: 1. 先使用 `mongoTemplate.count` 查询总条数。 2. 然后调用 `query.with(pageable)` 进行分页。 #### 改进后的代码 ```java // 总条数查询前,确保未调用 query.with(pageable) long total = mongoTemplate.count(query, OrderEntity.class); // 分页查询 query.with(pageable); List<OrderEntity> orderEntities = mongoTemplate.find(query, OrderEntity.class); ``` --- ### 问题二:条件类型匹配问题 #### 问题描述 MongoDB 的字段具有严格的类型匹配。例如,如果数据库中 `orderNumber` 的类型是 `Long`,而 Java 代码中传入的条件是 `String` 类型,查询时将不会返回匹配结果。 #### 解决方案 在构建查询条件时,确保 Java 中传入的值类型与 MongoDB 中的字段类型一致。对于需要转换的值,使用对应的类型转换方法。例如: ```java if (orderNumber != null && !orderNumber.isEmpty()) { query.addCriteria(Criteria.where("orderNumber").is(Long.valueOf(orderNumber))); } ``` ### 问题三:`regex` 查询的大小写匹配问题 使用 `Criteria.regex` 方法时,默认大小写敏感。如果需要忽略大小写,需要显式添加修饰符 `i`。 #### 解决方案 在 `regex` 方法中传入第二个参数: ```java query.addCriteria(Criteria.where("consignee").regex(consignee, "i")); ``` --- ### 问题四:日期范围查询以及 使用日期范围查询时,`Criteria.gte` 和 `Criteria.lte` 方法需要确保传入的值是Data日期类型(mongoDB日期是Data类型)。如果传入 `String` 类型值,查询可能失败。 #### 解决方案 确保 `beginTime` 和 `endTime` 是 `Date` 类型。可以使用工具类如 `SimpleDateFormat` 或 Java 8 的 `LocalDateTime` 转换字符串为日期: #### 范围区间 ```log // beginTime 和 endTime 添加为查询条件,但是 MongoDB 的 com.mongodb.BasicDocument 限制了只能有一个 createdAt 条件。 org.springframework.data.mongodb.InvalidMongoDbApiUsageException: Due to limitations of the com.mongodb.BasicDocument, you can't add a second 'createdAt' criteria. Query already contains '{ "createdAt" : { "gte" : { "date" : "2025-01-10T16:00:00Z"}}}' ``` ```java // 错误代码 if (beginTime != null) { query.addCriteria(Criteria.where("createdAt").gte(beginTime)); } if (endTime != null) { query.addCriteria(Criteria.where("createdAt").lte(endTime)); } // 正确代码 if (beginTime != null && endTime != null) { query.addCriteria(Criteria.where("createdAt").gte(beginTime).lte(endTime)); } else if (beginTime != null) { query.addCriteria(Criteria.where("createdAt").gte(beginTime)); } else if (endTime != null) { query.addCriteria(Criteria.where("createdAt").lte(endTime)); } ``` --- ### 问题五:分页结果与总条数的不一致 如果在查询条件中包含了动态字段(例如多条件组合查询),可能导致分页结果与总条数不一致。 #### 解决方案 确保分页查询和总条数查询使用相同的 `Query` 对象,并避免对条件进行动态修改。 --- ### 总结 在使用 MongoDB 实现分页与条件查询时,需注意以下几点: 1. **查询总条数时,不要对 `Query` 对象调用分页操作(`with(pageable)`)。** 2. **确保条件的类型与数据库字段的类型一致,必要时进行类型转换。** 3. **`regex` 查询时,显式设置大小写修饰符。** 4. **日期查询时,确保条件值为日期类型。** 5. **动态条件查询需谨慎,确保分页查询与总条数查询一致。** 最后修改:2025 年 01 月 16 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏