2つのドメインオブジェクトがあります。
@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に基づいて「タイプ」を更新する必要があるため、カスタムリポジトリインターフェース内に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.
}
プロパティ式
前の例に示すように、プロパティ式は管理対象エンティティの直接プロパティのみを参照できます。クエリの作成時に、解析されたプロパティが管理対象ドメインクラスのプロパティであることを既に確認しています。ただし、ネストされたプロパティを走査して制約を定義することもできます。個人が郵便番号を持つ住所を持っていると仮定します。その場合、メソッド名は
リストfindByAddressZipCode(ZipCode zipCode);プロパティtraversal x.address.zipCodeを作成します。解決アルゴリズムは、パーツ全体(AddressZipCode)をプロパティとして解釈することから始まり、その名前(大文字ではない)のプロパティのドメインクラスをチェックします。アルゴリズムが成功した場合、そのプロパティを使用します。そうでない場合、アルゴリズムはキャメルケース部分のソースを右側から頭と尾に分割し、対応するプロパティ(この例ではAddressZipとCode)を見つけようとします。アルゴリズムがそのヘッドを持つプロパティを見つけると、テールを取得し、そこからツリーを構築し続け、前述の方法でテールを分割します。最初の分割が一致しない場合、アルゴリズムは分割ポイントを左(Address、ZipCode)に移動して続行します。
これはほとんどの場合に機能するはずですが、アルゴリズムが間違ったプロパティを選択する可能性があります。 PersonクラスにもaddressZipプロパティがあるとします。アルゴリズムは、最初の分割ラウンドですでに一致し、本質的に間違ったプロパティを選択し、最終的に失敗します(addressZipのタイプにはおそらくコードプロパティがないため)。このあいまいさを解決するには、メソッド名内で_を使用して、トラバーサルポイントを手動で定義します。したがって、メソッド名は次のようになります。
UserDataRepository:
リストfindByAddress_ZipCode(ZipCode zipCode);
UserData findByUserId(String userId);
ProfileRepository:
プロファイルfindByProfileId(String profileId);
UserDataRepositoryImpl:
UserData userData = userDateRepository.findByUserId(userId);
プロファイル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(String email);
参照: http://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html
Mongo Aggregationフレームワークを使用する必要があります。
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;
これにより、提供userId
およびquestionId
に一致する結果のみが表示されます。
userId:1およびquestionId:111の結果:
{
"userId": "1",
"questions": {
"questionId": "111",
"type": "optional"
}
}