spring数据 - Mongodb - findBy嵌套对象的方法

use*_*083 23 findby mongodb spring-data

我有两个域对象,

@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
}
Run Code Online (Sandbox Code Playgroud)

我的JSON文档是这样的,

{
    "_id" : ObjectId("506d9c0ce4b005cb478c2e97"),
    "userId" : 1,
    "questions" : [
        {
            "questionID" : 1,
            "type" : "optional"

         },
        {
             "questionID" : 3,
             "type" : "mandatory"
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

我必须更新基于userId和questionId的"类型",所以我在自定义Repository接口中编写了一个findBy查询方法,

public interface CustomRepository extends MongoRepository<PracticeQuestion, String> {

    List<PracticeQuestion> findByUserIdAndQuestionsQuestionID(int userId,int questionID);       
}
Run Code Online (Sandbox Code Playgroud)

我的问题是当我执行此方法时userId为1而questionID为3,它返回整个问题列表而不管questionID.查询方法名称是有效的,还是应该如何为嵌套对象编写查询.

谢谢你的任何建议.

sbz*_*oom 31

只需@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);

}
Run Code Online (Sandbox Code Playgroud)

通过添加注释的fields一部分@Query,您告诉Mongo仅返回文档的该部分.但要注意,它仍然以相同的格式返回整个文档 - 只是缺少您未指定的所有内容.因此,您的代码仍然必须返回List<PracticeQuestion>,您将不得不这样做:

foreach (PracticeQuestion pq : practiceQuestions) {
    Question q = pq.getQuestions().get(0); // This should be your question.
}
Run Code Online (Sandbox Code Playgroud)


小智 14

属性表达式

属性表达式只能引用被管实体的直接属性,如前面的示例所示.在查询创建时,您已确保已解析的属性是托管域类的属性.但是,您也可以通过遍历嵌套属性来定义约束.假设人员拥有ZipCodes的地址.在这种情况下,方法名称为

列出findByAddressZipCode(ZipCode zipCode); 创建属性遍历x.address.zipCode.解析算法首先将整个部分(AddressZipCode)解释为属性,并检查域类中是否具有该名称的属性(未大写).如果算法成功,则使用该属性.如果没有,算法会将驼峰案例部分的源从右侧分成头部和尾部,并尝试查找相应的属性,在我们的示例中为AddressZip和Code.如果算法找到具有该头部的属性,则它采用尾部并继续从那里构建树,以刚刚描述的方式将尾部分开.如果第一个分割不匹配,算法将分割点移动到左侧(地址,ZipCode)并继续.

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

UserDataRepository:

列出findByAddress_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;
}
Run Code Online (Sandbox Code Playgroud)

对于存储库类中的上述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

  • 这是高质量的帖子 (3认同)
  • 这就是这个问题的确切答案。 (2认同)

Meh*_*lik 5

您需要使用 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();
Run Code Online (Sandbox Code Playgroud)

2)您需要创建一个类(因为展开操作改变了类结构),如下所示:

public class PracticeQuestionUnwind {
    private String userId;
    private Question questions;
Run Code Online (Sandbox Code Playgroud)

这只会给你那些匹配的结果提供userIdquestionId

userId: 1 和 questionId : 111 的结果:

{
    "userId": "1",
     "questions": {
                "questionId": "111",
                "type": "optional"
             }
 }
Run Code Online (Sandbox Code Playgroud)