Spring Data MongoDB @DocumentReference关联查询返回空问题
问题根因
- 配置
@DocumentReference(lazy = true)后,publishers集合的books字段仅存储关联书籍文档的ObjectId,不会存储title、isbn13等书籍的其他属性。 - 你之前编写的查询直接在
publishers集合上用elemMatch匹配books.title,是直接在MongoDB原始存储的文档上做条件匹配,此时books数组里只有ID值,不存在title字段,自然匹配不到结果返回空列表。 mongoTemplate.findAll(Publisher::class.java)能正常执行,是因为Spring Data MongoDB在查询到publisher的原始文档后,会自动根据books里存的ID批量去books集合查询对应书籍数据,组装成完整的Publisher实体返回,这个自动关联组装的逻辑不会作用在你自定义的查询条件上。
可行实现方案
完全可以实现你的需求,不需要修改现有实体的lazy = true配置,推荐用两步查询的方案实现,性能高且逻辑简单:
- 先查询
books集合,拿到标题为Title1的所有书籍的ID列表 - 再查询
publishers集合,匹配books数组中包含上述任意书籍ID的文档即可
示例代码如下:
@GetMapping("/find") fun findPublishers(): MutableList<Publisher> { // 第一步:查询目标书籍的ID集合 val targetBookIds = mongoTemplate.findDistinct( Query(Criteria.where("title").`is`("Title1")), "id", Book::class.java, ObjectId::class.java ) // 没有匹配的书籍直接返回空列表 if (targetBookIds.isEmpty()) { return mutableListOf() } // 第二步:根据书籍ID匹配关联的出版社 val publisherQuery = Query().addCriteria( Criteria.where("books").`in`(targetBookIds) ) return mongoTemplate.find(publisherQuery, Publisher::class.java) }
返回结果时Spring Data会自动完成书籍属性的懒加载,和findAll接口返回的实体结构完全一致,同时publishers集合里也只会存储关联书籍的ID,没有冗余字段。
如果后续需要更复杂的跨集合关联查询条件,也可以直接使用MongoDB的聚合管道$lookup操作实现:
@GetMapping("/find") fun findPublishers(): MutableList<Publisher> { val aggregation = Aggregation.newAggregation( // 关联books集合,将publishers.books和books._id做匹配,关联结果存到临时字段bookRefs Aggregation.lookup("books", "books", "_id", "bookRefs"), // 匹配关联结果中标题为Title1的文档 Aggregation.match(Criteria.where("bookRefs.title").`is`("Title1")), // 排除临时关联字段,避免影响实体映射 Aggregation.project().andExclude("bookRefs") ) return mongoTemplate.aggregate( aggregation, "publishers", Publisher::class.java ).mappedResults }
注意:不建议为了简化查询关闭lazy配置、将书籍全字段冗余存储在publishers集合中,这种方案会带来严重的数据一致性问题,每次书籍信息更新都需要同步修改所有关联该书籍的出版社文档,维护成本会随数据量增长急剧升高。
内容的提问来源于stack exchange,提问作者trom
相关产品推荐
相关产品推荐

