You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Data MongoDB @Query SpEL报EL1043E错误如何解决

问题背景

需要实现多条件动态过滤的MongoDB分页查询,其中文件名过滤逻辑为:当传入的文件名正则模式列表不为空时,筛选出文件名匹配列表中任意一个正则模式的记录。该逻辑对应的MongoDB原生语句可直接在客户端正常执行,但写在Spring Data MongoDB的@Query注解中时抛出解析错误:

Expression [ #fileNames == null or #fileNames.isEmpty() ? {$expr : 'true'} : { $expr: { $gt: [ { $size: { $filter: { input: #fileNames, as: 'pattern', cond: { $regexMatch: { input: '$fileName', regex: '$$pattern' } } } } }, 0 ] } } ] @212: EL1043E: Unexpected token. Expected 'rsquare(])' but was 'comma(,)'

原有查询定义代码如下:

@Query("{ $and :["
    + "?#{ #users == null or #users.isEmpty() ? {$expr : 'true'} : { 'userName' : {$in : #users} } },"
    + "?#{ #fileNamePatterns== null or #fileNamePatterns.isEmpty() ? {$expr : 'true'} : { $expr: { $gt: [ { $size: { $filter: { input: #fileNamePatterns, as: 'pattern', cond: { $regexMatch: { input: '$fileName', regex: '$$pattern' } } } } }, 0 ] } } },"
    + "?#{ #from == null ? {$expr : 'true'} : { 'timestamp' : {$gte : #from} } },"
    + "?#{ #to == null ? {$expr : 'true'} : { 'timestamp' : {$lte : #to} } }"
    + "]}")
Page<FileHistory> findHistory(List<String> users, List<String> fileNamePatterns, LocalDateTime from, LocalDateTime to, Pageable pageable);

对应实体类定义:

public class FileHistory {

  @Id
  private ObjectId fileId;
  private String fileName;
  private String userName;
  private LocalDateTime timestamp;

}
错误原因

报错是SpEL(Spring表达式语言)解析阶段的语法错误,不是MongoDB的语法错误:

  • ?#{ ... }包裹的内容会被SpEL优先解析,直接在三目表达式的返回分支写嵌套的MongoDB JSON结构(包含大括号、数组中括号、逗号)时,SpEL会把这些JSON语法符号当成SpEL自身的表达式语法去解析
  • 碰到$gt: [xxx, 0]里的逗号时,SpEL认为数组应该在逗号前闭合,因此抛出"期待右中括号但遇到逗号"的错误
修复方案

将三目分支中不需要SpEL解析内部结构的MongoDB原生JSON片段,用单引号包裹为SpEL字符串字面量,片段内部的单引号用两个连续单引号做转义即可,SpEL会直接将字符串内容拼接为最终的查询JSON,不会解析内部的语法符号。

修复后的查询定义:

@Query("{ $and : ["
    + "?#{ #users == null or #users.isEmpty() ? '{$expr: true}' : { 'userName' : {$in : #users} } },"
    + "?#{ #fileNamePatterns == null or #fileNamePatterns.isEmpty() ? '{$expr: true}' : '{$expr: { $gt: [ { $size: { $filter: { input: #fileNamePatterns, as: ''pattern'', cond: { $regexMatch: { input: ''$fileName'', regex: ''$$pattern'' } } } } }, 0 ] } }' },"
    + "?#{ #from == null ? '{$expr: true}' : { 'timestamp' : {$gte : #from} } },"
    + "?#{ #to == null ? '{$expr: true}' : { 'timestamp' : {$lte : #to} } }"
    + "]}")
Page<FileHistory> findHistory(List<String> users, List<String> fileNamePatterns, LocalDateTime from, LocalDateTime to, Pageable pageable);

注意点

  • 包裹在单引号内的JSON片段中,引用的方法参数(比如#fileNamePatterns)依然会被SpEL正确识别、替换为对应参数值,不需要额外做字符串拼接
  • 所有固定的MongoDB语法片段如果包含复杂嵌套结构、数组、逗号,都建议用单引号包裹为字符串字面量,避免触发SpEL的语法解析冲突

内容的提问来源于stack exchange,提问作者Kronen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 04:03:23