spring 数据 - Mongodb - 嵌套对象的 findBy 方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12730370/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
spring data - Mongodb - findBy Method for nested objects
提问by user1720083
I have two domain objects,
我有两个域对象,
@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
}
My JSON doc is like this,
我的 JSON 文档是这样的,
{
"_id" : ObjectId("506d9c0ce4b005cb478c2e97"),
"userId" : 1,
"questions" : [
{
"questionID" : 1,
"type" : "optional"
},
{
"questionID" : 3,
"type" : "mandatory"
}
]
}
I have to update the "type" based on userId and questionId, so I have written a findBy query method inside the custom Repository interface,
我必须根据 userId 和 questionId 更新“类型”,所以我在自定义 Repository 接口中编写了一个 findBy 查询方法,
public interface CustomRepository extends MongoRepository<PracticeQuestion, String> {
List<PracticeQuestion> findByUserIdAndQuestionsQuestionID(int userId,int questionID);
}
My problem is when I execute this method with userId as 1 and questionID as 3, it returns the entire questions list irrespective of the questionID. Is the query method name valid or how should I write the query for nested objects.
我的问题是,当我使用 userId 为 1 和 questionID 为 3 执行此方法时,它会返回整个问题列表,而不管 questionID。查询方法名称是否有效,或者我应该如何编写嵌套对象的查询。
Thanks for any suggestion.
感谢您的任何建议。
回答by sbzoom
Just use the @Query
annotation on that method.
只需@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);
}
By adding the fields
part of the @Query
annotation, you are telling Mongo to only return that part of the document. Beware though, it still returns the entire document in the same format - just missing everything you did not specify. So your code will still have to return List<PracticeQuestion>
and you will have to do:
通过添加注释的fields
一部分@Query
,你告诉 Mongo 只返回文档的那部分。但请注意,它仍然以相同的格式返回整个文档——只是缺少您未指定的所有内容。所以你的代码仍然必须返回List<PracticeQuestion>
,你必须这样做:
foreach (PracticeQuestion pq : practiceQuestions) {
Question q = pq.getQuestions().get(0); // This should be your question.
}
回答by Govardhana Rao Ganji
Property expressions
属性表达式
Property expressions can refer only to a direct property of the managed entity, as shown in the preceding example. At query creation time you already make sure that the parsed property is a property of the managed domain class. However, you can also define constraints by traversing nested properties. Assume Persons have Addresses with ZipCodes. In that case a method name of List<Person> findByAddressZipCode(ZipCode zipCode);
creates the property traversal x.address.zipCode. The resolution algorithm starts with interpreting the entire part (AddressZipCode) as the property and checks the domain class for a property with that name (uncapitalized). If the algorithm succeeds it uses that property. If not, the algorithm splits up the source at the camel case parts from the right side into a head and a tail and tries to find the corresponding property, in our example, AddressZip and Code. If the algorithm finds a property with that head it takes the tail and continue building the tree down from there, splitting the tail up in the way just described. If the first split does not match, the algorithm move the split point to the left (Address, ZipCode) and continues.
属性表达式只能引用托管实体的直接属性,如前面的示例所示。在创建查询时,您已经确保解析的属性是托管域类的属性。但是,您也可以通过遍历嵌套属性来定义约束。假设人们有带有邮政编码的地址。在这种情况下,方法名称为List<Person> findByAddressZipCode(ZipCode zipCode);
创建属性遍历 x.address.zipCode。解析算法首先将整个部分 (AddressZipCode) 解释为属性,并检查具有该名称(未大写)的属性的域类。如果算法成功,它将使用该属性。如果没有,该算法会从右侧将驼峰部分的源分成头部和尾部,并尝试找到相应的属性,在我们的示例中为 AddressZip 和 Code。如果算法找到具有该头部的属性,它会取尾部并继续从那里向下构建树,以刚才描述的方式将尾部拆分。如果第一个拆分不匹配,则算法将拆分点向左移动(地址、邮政编码)并继续。
Although this should work for most cases, it is possible for the algorithm to select the wrong property. Suppose the Person class has an addressZip property as well. The algorithm would match in the first split round already and essentially choose the wrong property and finally fail (as the type of addressZip probably has no code property). To resolve this ambiguity you can use _ inside your method name to manually define traversal points. So our method name would end up like so:
尽管这应该适用于大多数情况,但算法可能会选择错误的属性。假设 Person 类也有一个 addressZip 属性。该算法将在第一轮分割中匹配,并且本质上选择了错误的属性并最终失败(因为 addressZip 的类型可能没有代码属性)。要解决这种歧义,您可以在方法名称中使用 _ 来手动定义遍历点。所以我们的方法名称最终会像这样:
UserDataRepository:
用户数据存储库:
List<UserData> findByAddress_ZipCode(ZipCode zipCode);
UserData findByUserId(String userId);
ProfileRepository:
配置文件库:
Profile findByProfileId(String profileId);
UserDataRepositoryImpl:
UserDataRepositoryImpl:
UserData userData = userDateRepository.findByUserId(userId);
Profile profile = profileRepository.findByProfileId(userData.getProfileId());
userData.setProfile(profile);
Sample Pojo :
示例 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;
}
For the above Document/POJO in your Repository Class:
对于存储库类中的上述文档/POJO:
UserData findByProfile_Email(String email);
UserData findByProfile_Email(String email);
For ref : http://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html
对于参考:http: //docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html
回答by Mehraj Malik
You need to use Mongo Aggregation framework :
您需要使用 Mongo 聚合框架:
1) Create custom method for mongo repository : Add custom method to Repository
1) 为 mongo 存储库创建自定义方法:将自定义方法添加到存储库
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) You need to cretae a class(Because unwind operation has changed the class structure) like below :
2)您需要创建一个类(因为展开操作改变了类结构),如下所示:
public class PracticeQuestionUnwind {
private String userId;
private Question questions;
This will give you only those result which matches the provide userId
and questionId
这只会给你那些与提供userId
和 匹配的结果questionId
Result for userId: 1 and questionId : 111 :
userId: 1 和 questionId : 111 的结果:
{
"userId": "1",
"questions": {
"questionId": "111",
"type": "optional"
}
}