Spring Boot中MongoDB对象数组查询报$elemMatch错误求助
问题排查与解决:MongoDB查询$elemMatch报错"$elemMatch needs an Object"
问题背景
现有指定结构的MongoDB集合文档,需实现短语搜索+检查meta数组中存在指定index_field_id的查询功能,但编写的Spring Data MongoDB查询方法运行时抛出异常。
MongoDB文档结构
{ "_id": "ba4d5a0e-1759-4e88-bd57-5e7781d46da7", "name": "Doc 3 updated", "documentClass": "033a1f67-b382-43f5-b1e4-7ade26f1522c", "documentClassName": "Sample Document", "meta": [ { "index_field_id": "9e744f36-1c63-45e8-8180-3ceef894b724", "value": "a" }, { "index_field_id": "08afba06-9a7e-4df8-a946-a8cccbefda8b", "value": "asafsf" } ], "version": 2, "archived": false, "checkedOut": false, "checkedOutBy": "svpadm", "created": { "$date": "2023-12-24T11:12:39.580Z" }, "modified": { "$date": "2024-01-09T19:48:29.785Z" }, "owner": "79866869-398a-4920-975b-032decc12461", "ownerClear": "svpadm", "tenant": "ECMDEV01-T", "updatedBy": "79866869-398a-4920-975b-032decc12461", "updatedByClear": "svpadm", "_class": "de.metasonic.cloud.models.database.Document" }
需求说明
- 通过指定短语搜索文档,匹配字段包括:
name、documentClass、documentClassName、workbookId、owner、ownerClear、tenant、updatedBy、updatedByClear、linkedDocuments、providerState、providerMetaData,匹配时忽略大小写。 - 同时筛选出
meta数组中存在indexFieldIds列表中任一index_field_id的文档。
原查询方法
@Query("{$and: [" + " {$or: [" + " {'name': {$regex: ?0, $options: 'i'}}, " + " {'documentClass': {$regex: ?0, $options: 'i'}}, " + " {'documentClassName': {$regex: ?0, $options: 'i'}}, " + " {'workbookId': {$regex: ?0, $options: 'i'}}, " + " {'owner': {$regex: ?0, $options: 'i'}}, " + " {'ownerClear': {$regex: ?0, $options: 'i'}}, " + " {'tenant': {$regex: ?0, $options: 'i'}}, " + " {'updatedBy': {$regex: ?0, $options: 'i'}}, " + " {'updatedByClear': {$regex: ?0, $options: 'i'}}, " + " {'linkedDocuments': {$elemMatch: {$regex: ?0, $options: 'i'}}}, " + " {'providerState': {$regex: ?0, $options: 'i'}}, " + " {'providerMetaData': {$elemMatch: {$regex: ?0, $options: 'i'}}}" + " ]}, " + " {'meta': {$elemMatch: {'index_field_id': {$in: ?1}}}}" + "]}") Page<Document> searchByPhraseAndIndexFieldIds(String searchPhrase, List<String> indexFieldIds, Pageable pageable);
对应的DTO类
public class DocumentMetaDTO { String index_field_id; Object value; ArrayList<DocumentMetaDTO> categoryValues; }
异常信息
Exception : org.springframework.data.mongodb.UncategorizedMongoDbException: Query failed with error code 2 with name 'BadValue' and error message '$elemMatch needs an Object' on server localhost:27018; nested exception is com.mongodb.MongoQueryException: Query failed with error code 2 with name 'BadValue' and error message '$elemMatch needs an Object' on server localhost:27018
问题原因
报错核心是错误使用$elemMatch操作符:
$elemMatch用于匹配数组中嵌套对象同时满足多个条件的元素,若只是匹配数组中的字符串元素是否符合正则,无需使用$elemMatch,直接对数组字段用正则即可,MongoDB会自动匹配数组中任意满足条件的元素。原查询中linkedDocuments和providerMetaData字段若为字符串数组,用$elemMatch包裹正则属于错误用法。- 针对
meta数组的查询仅需匹配index_field_id在指定列表中,无需$elemMatch,直接通过meta.index_field_id路径查询更简洁高效。
修正后的查询方法
@Query("{$and: [" + " {$or: [" + " {'name': {$regex: ?0, $options: 'i'}}, " + " {'documentClass': {$regex: ?0, $options: 'i'}}, " + " {'documentClassName': {$regex: ?0, $options: 'i'}}, " + " {'workbookId': {$regex: ?0, $options: 'i'}}, " + " {'owner': {$regex: ?0, $options: 'i'}}, " + " {'ownerClear': {$regex: ?0, $options: 'i'}}, " + " {'tenant': {$regex: ?0, $options: 'i'}}, " + " {'updatedBy': {$regex: ?0, $options: 'i'}}, " + " {'updatedByClear': {$regex: ?0, $options: 'i'}}, " + " {'linkedDocuments': {$regex: ?0, $options: 'i'}}, " + " {'providerState': {$regex: ?0, $options: 'i'}}, " + " {'providerMetaData': {$regex: ?0, $options: 'i'}}" + " ]}, " + " {'meta.index_field_id': {$in: ?1}}" + "]}") Page<Document> searchByPhraseAndIndexFieldIds(String searchPhrase, List<String> indexFieldIds, Pageable pageable);
修正点说明
- 移除
linkedDocuments和providerMetaData字段查询中的$elemMatch,直接使用正则匹配数组元素。 - 将
meta数组的查询从{'meta': {$elemMatch: {'index_field_id': {$in: ?1}}}}改为{'meta.index_field_id': {$in: ?1}},无需$elemMatch即可实现匹配数组中任一元素的index_field_id在指定列表中的需求。
内容的提问来源于stack exchange,提问作者Viranga
相关产品推荐
相关产品推荐

