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);
}

通过添加@Query注释的fields部分,您告诉Mongo只返回文档的该部分。不过要注意,它仍然以相同的格式返回整个文档——只是缺少您没有指定的所有内容。因此,您的代码仍然必须返回List<PracticeQuestion>,并且您必须执行以下操作:

foreach (PracticeQuestion pq : practiceQuestions) {
Question q = pq.getQuestions().get(0); // This should be your question.
}
属性表达式

属性表达式只能引用托管实体的直接属性,如前面的示例所示。在创建查询时,您已经确保解析的属性是托管域类的属性。但是,也可以通过遍历嵌套特性来定义约束。假设个人拥有ZipCode地址。在这种情况下,方法名为List<Person> findByAddressZipCode(ZipCode zipCode);创建属性遍历x.address.zip代码。解析算法首先将整个部分(AddressZipCode)解释为属性,并检查域类中是否有该名称(未大写)的属性。如果算法成功,它将使用该属性。如果不是,该算法会将驼色大小写部分的源从右侧拆分为头和尾,并试图找到相应的属性,在我们的示例中是AddressZip和Code。如果算法找到了一个具有该头部的属性,它会取下尾部,并从那里继续构建树,以刚才描述的方式将尾部向上拆分。如果第一个拆分不匹配,则算法将拆分点向左移动(Address,ZipCode)并继续。

尽管这应该适用于大多数情况,但算法可能选择了错误的属性。假设Person类也有一个addressZip属性。该算法在第一轮拆分中已经匹配,基本上选择了错误的属性,最终失败(因为addressZip的类型可能没有代码属性)。为了解决这种歧义,您可以在方法名称中使用_来手动定义遍历点。所以我们的方法名称最终会是这样的:

UserDataRepository:

List<UserData> findByAddress_ZipCode(ZipCode zipCode);
UserData findByUserId(String userId);

档案库:

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;
}

对于存储库类中的上述文档/POJO:

UserData findByProfile_Email(字符串电子邮件)

供参考:http://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html

您需要使用Mongo聚合框架:

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) 你需要创建一个类(因为展开操作改变了类结构),如下所示:

public class PracticeQuestionUnwind {
private String userId;
private Question questions;

这将只为您提供与提供的userIdquestionId匹配的结果

用户ID:1和问题ID:111的结果:

{
"userId": "1",
"questions": {
"questionId": "111",
"type": "optional"
}
}

我也有类似的问题。为此,我在嵌套类属性之前添加了$。尝试以下查询

@Query(value = "{ 'userId' : ?0, 'questions.$questionID' : ?1 }") List<PracticeQuestion> findPracticeQuestionByUserIdAndQuestionsQuestionID(int userId, int questionID);

最新更新