使用Querydsl查询MongoDB中DocumentReference关联文档的问题
解决Spring Data MongoDB中Querydsl查询@DocumentReference关联字段的问题
你遇到的核心问题是:@DocumentReference本质是MongoDB的DBRef关联,它只在Subject集合中存储关联对象的引用($ref和$id结构),而非嵌入整个SubjectType文档。Querydsl的QuerydslPredicateExecutor生成的查询是直接针对Subject集合的,无法自动跨集合关联查询SubjectType的字段,所以直接查关联字段会返回空结果。以下是几种可行的解决方式:
1. 直接查询DBRef的存储结构
如果只是查询关联的SubjectType ID,直接针对MongoDB中DBRef的存储格式写Predicate即可。Querydsl生成的元模型会将subjectType.id映射为Subject文档中的subjectType.$id字段,直接匹配就能得到结果:
QSubject subject = QSubject.subject; // 匹配关联SubjectType的ID Predicate predicate = subject.subjectType.id.eq(new ObjectId("60d21b4667d0d8992e610c85")); List<Subject> result = subjectRepository.findAll(predicate);
2. 用聚合$lookup实现跨集合字段查询
如果需要查询SubjectType的非ID字段(比如name、code等),必须借助MongoDB的$lookup聚合操作来关联两个集合,再进行过滤。可以直接用MongoTemplate编写聚合逻辑:
Aggregation aggregation = Aggregation.newAggregation( // 关联SubjectType集合,将匹配结果存入subjectTypeDetails字段 Aggregation.lookup("subjectType", "subjectType.$id", "_id", "subjectTypeDetails"), // 过滤关联后SubjectType的name字段 Aggregation.match(Criteria.where("subjectTypeDetails.name").is("Mathematics")), // 按需投影字段,将关联结果映射回subjectType属性 Aggregation.project("title", "description").and("subjectTypeDetails").as("subjectType") ); AggregationResults<Subject> results = mongoTemplate.aggregate(aggregation, "subject", Subject.class); List<Subject> subjectList = results.getMappedResults();
如果想结合Querydsl,可以用Querydsl生成的Predicate替换match中的Criteria,保持代码风格统一。
3. 自定义Repository方法
在Repository接口中通过@Query注解直接编写MongoDB查询语句,灵活处理DBRef或聚合场景:
- 查询关联ID:
@Repository public interface SubjectRepository extends MongoRepository<Subject, ObjectId>, QuerydslPredicateExecutor<Subject> { @Query("{ 'subjectType.$id': ?0 }") List<Subject> findBySubjectTypeId(ObjectId subjectTypeId); }
- 查询关联字段(基于聚合):
@Repository public interface SubjectRepository extends MongoRepository<Subject, ObjectId>, QuerydslPredicateExecutor<Subject> { @Query(value = "[{ '$lookup': { 'from': 'subjectType', 'localField': 'subjectType.$id', 'foreignField': '_id', 'as': 'subjectTypeDetails' } }, { '$match': { 'subjectTypeDetails.name': ?0 } }]") List<Subject> findBySubjectTypeName(String typeName); }
关键注意点
@DocumentReference默认是懒加载,查询Subject实体后访问subjectType属性会触发额外的单条查询,但这和Querydsl的集合查询是两回事——Querydsl无法在集合查询阶段自动关联加载SubjectType数据。- 确保Querydsl元模型正确生成,比如在pom.xml中配置Querydsl的MongoDB处理器,保证Q类能正确识别
@DocumentReference关联的字段结构。
内容的提问来源于stack exchange,提问作者Mario Biagioni
相关产品推荐
相关产品推荐

