使用SpEL在@Query中无法将String转为Decimal128问题排查
问题分析与修复方案
1. SpEL表达式语法错误
你在value字段的查询逻辑里存在语法问题:
- 多余的闭合括号:
{'value': '?#{...}}'}中多了一个},应修正为{'value': ?#{...}} - 不必要的单引号:
T(org.bson.types.Decimal128).parse(...)返回的是Decimal128对象,而非字符串,加单引号会强制转成字符串,导致数据库字段类型不匹配,直接使用?#{...}即可。
2. 正则表达式转义与逻辑缺陷
你写的正则"-?\\\\d+(\\\\.\\\\d+)?"在Java字符串中会被解析为"-?\\d+(\\.\\d+)?",这本身是正确的,但当前逻辑存在问题:当search不匹配数字格式时,会返回Decimal128.parse("0.0"),这会导致查询所有value=0.0的记录,而非跳过该条件,不符合模糊查询的预期。
3. 跨类型匹配错误
paymentDate、dueDate是日期类型,payed是布尔类型,你直接用字符串类型的?0去匹配,会触发数据库类型不匹配错误,无法正确执行查询。这类字段需要先判断search是否符合对应类型格式,再做转换匹配。
4. 参数引用的场景混淆
?0对应方法的第一个参数search,但只有description、type这类字符串类型字段适合直接匹配,其他类型字段必须做格式校验和类型转换。
修复后的代码示例
public interface ExpenseCollectionRepository extends ReactiveMongoRepository<ExpenseCollection, String> { Mono<Boolean> existsByDescriptionAndDueDate(String description, LocalDate dueDate); @Query("{'$or': [" + "{'description': ?0}, " + "?#{#search.matches('-?\\\\d+(\\\\.\\\\d+)?') ? {'value': T(org.bson.types.Decimal128).parse(#search)} : {}}, " + "?#{#search.matches('\\\\d{4}-\\\\d{2}-\\\\d{2}') ? {'paymentDate': T(java.time.LocalDate).parse(#search)} : {}}, " + "?#{#search.matches('\\\\d{4}-\\\\d{2}-\\\\d{2}') ? {'dueDate': T(java.time.LocalDate).parse(#search)} : {}}, " + "{'type': ?0}, " + "?#{#search.matches('true|false') ? {'payed': T(java.lang.Boolean).parseBoolean(#search)} : {}} " + "]}") Flux<ExpenseCollection> findPage(@Param("search") String search, Pageable pageable); }
此代码的核心优化:当search不符合对应字段的格式时,该条件会转为空对象{},不会参与$or查询,避免类型错误和解析异常。
额外注意事项
- ReactiveMongoRepository会自动将
Pageable转换为MongoDB的skip和limit逻辑,确保返回分页后的结果。 - 正则匹配规则需根据实际数据格式调整,比如日期格式是否为
yyyy-MM-dd、布尔值是否为小写的true/false。
内容的提问来源于stack exchange,提问作者Sergio Luigi Alves
相关产品推荐
相关产品推荐

