spring data - Mongodb - findBy 嵌套对象的方法
Posted
技术标签:
【中文标题】spring data - Mongodb - findBy 嵌套对象的方法【英文标题】:spring data - Mongodb - findBy Method for nested objects 【发布时间】:2012-09-25 16:08:15 【问题描述】:我有两个域对象,
@Document
public class PracticeQuestion
private int userId;
private List<Question> questions;
// Getters and setters
@Document
public class Question
private int questionID;
private String type;
// Getters and setters
我的 JSON 文档是这样的,
"_id" : ObjectId("506d9c0ce4b005cb478c2e97"),
"userId" : 1,
"questions" : [
"questionID" : 1,
"type" : "optional"
,
"questionID" : 3,
"type" : "mandatory"
]
我要根据userId和questionId更新“类型”,所以我在自定义Repository接口里面写了一个findBy查询方法,
public interface CustomRepository extends MongoRepository<PracticeQuestion, String>
List<PracticeQuestion> findByUserIdAndQuestionsQuestionID(int userId,int questionID);
我的问题是,当我使用 userId 为 1 和 questionID 为 3 执行此方法时,它会返回整个问题列表,而与 questionID 无关。查询方法名称是否有效或者我应该如何编写嵌套对象的查询。
感谢您的任何建议。
【问题讨论】:
【参考方案1】:只需在该方法上使用@Query
注释即可。
public interface CustomRepository extends MongoRepository<PracticeQuestion, String>
@Query(value = " 'userId' : ?0, 'questions.questionID' : ?1 ", fields = " 'questions.questionID' : 1 ")
List<PracticeQuestion> findByUserIdAndQuestionsQuestionID(int userId, int questionID);
通过添加@Query
注释的fields
部分,您是在告诉Mongo 只返回文档的该部分。但请注意,它仍然以相同的格式返回整个文档 - 只是丢失了您未指定的所有内容。所以你的代码仍然需要返回List<PracticeQuestion>
,你必须这样做:
foreach (PracticeQuestion pq : practiceQuestions)
Question q = pq.getQuestions().get(0); // This should be your question.
【讨论】:
感谢您的回复,但此查询再次返回一个数组,而不是数组中的适当元素。 哦。我明白你的意思了。您只能返回整个文档。该查询实际上查找具有该 questionID 的文档。但是您总是会返回整个文档 - 而不仅仅是问题。这不是 java 的东西,它是 MongoDB 的东西。请查看此问题/答案以进行澄清:***.com/a/3985982/229178 经过一些功课,我意识到您可以在查询的fields
部分(projections
)中指定部分对象。 mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields我会更新我上面的答案来举个例子。
谢谢,同时我也试试看。
它也适用于 ReactiveMongoRepository 吗?它对我不起作用:@Query("'properties.brand' : ?0, 'properties.capacity' : ?1 ") Flux属性表达式
属性表达式只能引用托管实体的直接属性,如前面的示例所示。在创建查询时,您已经确保解析的属性是托管域类的属性。但是,您也可以通过遍历嵌套属性来定义约束。假设人员有带有邮政编码的地址。在这种情况下,方法名称为 List<Person> findByAddressZipCode(ZipCode zipCode);
创建属性遍历 x.address.zipCode。解析算法首先将整个部分 (AddressZipCode) 解释为属性,并检查域类中具有该名称(未大写)的属性。如果算法成功,它将使用该属性。如果不是,该算法将源在驼峰部分从右侧拆分为头部和尾部,并尝试找到相应的属性,在我们的示例中为 AddressZip 和 Code。如果算法找到具有该头部的属性,它将获取尾部并继续从那里向下构建树,以刚才描述的方式将尾部拆分。如果第一次拆分不匹配,算法将拆分点向左移动(地址,邮政编码)并继续。
虽然这应该适用于大多数情况,但算法可能会选择错误的属性。假设 Person 类也有一个 addressZip 属性。该算法已经在第一个拆分轮中匹配,并且基本上选择了错误的属性并最终失败(因为 addressZip 的类型可能没有 code 属性)。要解决这种歧义,您可以在方法名称中使用 _ 来手动定义遍历点。所以我们的方法名最终会是这样的:
用户数据存储库:
List<UserData> findByAddress_ZipCode(ZipCode zipCode);
UserData findByUserId(String userId);
ProfileRepository:
Profile findByProfileId(String profileId);
UserDataRepositoryImpl:
UserData userData = userDateRepository.findByUserId(userId);
Profile profile = profileRepository.findByProfileId(userData.getProfileId());
userData.setProfile(profile);
Pojo 示例:
public class UserData
private String userId;
private String status;
private Address address;
private String profileId;
//New Property
private Profile profile;
//TODO:setter & getter
public class Profile
private String email;
private String profileId;
对于您的 Repository 类中的上述 Document/POJO:
UserData findByProfile_Email(String email);
参考:http://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html
【讨论】:
这是高质量的帖子 这是这个问题的确切答案。【参考方案3】:你需要使用 Mongo 聚合框架:
1) 为 mongo 存储库创建自定义方法:Add custom method to Repository
UnwindOperation unwind = Aggregation.unwind("questions");
MatchOperation match = Aggregation.match(Criteria.where("userId").is(userId).and("questions.questionId").is(questionID));
Aggregation aggregation = Aggregation.newAggregation(unwind,match);
AggregationResults<PracticeQuestionUnwind> results = mongoOperations.aggregate(aggregation, "PracticeQuestion",
PracticeQuestionUnwind.class);
return results.getMappedResults();
2) 你需要创建一个类(因为展开操作改变了类结构),如下所示:
public class PracticeQuestionUnwind
private String userId;
private Question questions;
这只会为您提供与 userId
和 questionId
匹配的结果
userId:1 和 questionId:111 的结果:
"userId": "1",
"questions":
"questionId": "111",
"type": "optional"
【讨论】:
【参考方案4】:我也有类似的问题。为此,我在嵌套类属性之前添加了 $。 试试下面的查询
@Query(value = " 'userId' : ?0, 'questions.$questionID' : ?1 ") List<PracticeQuestion> findPracticeQuestionByUserIdAndQuestionsQuestionID(int userId, int questionID);
【讨论】:
以上是关于spring data - Mongodb - findBy 嵌套对象的方法的主要内容,如果未能解决你的问题,请参考以下文章
Spring -Data MongoDB问题与作为接口的字段
使用Spring访问Mongodb的方法大全——Spring Data MongoDB
如何在 spring-boot 中禁用 spring-data-mongodb 自动配置