spring数据 - Mongodb - findBy嵌套对象的方法
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring数据 - Mongodb - findBy嵌套对象的方法相关的知识,希望对你有一定的参考价值。
我有两个域对象,
@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。查询方法名称是有效的,还是应该如何为嵌套对象编写查询。
谢谢你的任何建议。
只需在该方法上使用@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);
}
通过添加fields
注释的@Query
部分,您告诉Mongo仅返回文档的该部分。但要注意,它仍然以相同的格式返回整个文档 - 只是缺少您未指定的所有内容。因此,您的代码仍然必须返回List<PracticeQuestion>
,您将不得不这样做:
foreach (PracticeQuestion pq : practiceQuestions) {
Question q = pq.getQuestions().get(0); // This should be your question.
}
属性表达式
属性表达式只能引用被管实体的直接属性,如前面的示例所示。在查询创建时,您已确保已解析的属性是托管域类的属性。但是,您也可以通过遍历嵌套属性来定义约束。假设人员拥有ZipCodes的地址。在这种情况下,方法名称为
列出findByAddressZipCode(ZipCode zipCode);创建属性遍历x.address.zipCode。解析算法首先将整个部分(AddressZipCode)解释为属性,并检查域类中是否具有该名称的属性(未大写)。如果算法成功,则使用该属性。如果没有,算法将来自右侧的驼峰案例部分的源分成头部和尾部,并尝试找到相应的属性,在我们的示例中,AddressZip和Code。如果算法找到具有该头部的属性,则它采用尾部并继续从那里构建树,以刚刚描述的方式将尾部分开。如果第一个分割不匹配,算法将分割点移动到左侧(地址,ZipCode)并继续。
虽然这应该适用于大多数情况,但算法可能会选择错误的属性。假设Person类也有一个addressZip属性。该算法将在第一个拆分轮中匹配,并且基本上选择了错误的属性并最终失败(因为addressZip的类型可能没有代码属性)。要解决这种歧义,可以在方法名称中使用_来手动定义遍历点。所以我们的方法名称最终会像这样:
UserDataRepository:
列表查找按地址ZipCode(ZipCode zipCode);
UserData findByUserId(String userId);
ProfileRepository:
配置文件findByProfileId(String profileId);
UserDataRepositoryImpl:
UserData userData = userDateRepository.findByUserId(userId);
Profile profile = profileRepository.findByProfileId(userData.getProfileId());
userData.setProfile(配置文件);
示例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;
}
对于存储库类中的上述Document / POJO:
UserData findByProfile_Email(String email);
对于ref:http://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html
您需要使用Mongo Aggregation框架:
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"
}
}
以上是关于spring数据 - Mongodb - findBy嵌套对象的方法的主要内容,如果未能解决你的问题,请参考以下文章
mongodb的find查询10万条以上的数据有卡顿现象,请问如何选择优化的方式
使用 Spring Boot 和 MongoTemplate 对 MongoDB 结果进行排序