Spring Data MongoDBのクエリガイド
1. 概要
この記事では、さまざまなtypes of queries in Spring Data MongoDBの構築に焦点を当てます。
QueryクラスとCriteriaクラス、自動生成されたクエリメソッド、JSONクエリ、QueryDSLを使用したドキュメントのクエリについて見ていきます。
Mavenのセットアップについては、introductory articleをご覧ください。
2. ドキュメントクエリ
Spring Dataを使用してMongoDBにクエリを実行する最も一般的な方法の1つは、QueryクラスとCriteriaクラスを使用することです。これらはネイティブ演算子を非常によく反映しています。
2.1. Is
これは単に平等を使用する基準です–それがどのように機能するか見てみましょう。
次の例では、Ericという名前のユーザーを探しています。
私たちのデータベースを見てみましょう:
[
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.example.model.User",
"name" : "Eric",
"age" : 45
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581908"),
"_class" : "org.example.model.User",
"name" : "Antony",
"age" : 55
}
}
次に、クエリコードを見てみましょう。
Query query = new Query();
query.addCriteria(Criteria.where("name").is("Eric"));
List users = mongoTemplate.find(query, User.class);
予想どおり、このロジックは戻ります。
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.example.model.User",
"name" : "Eric",
"age" : 45
}
2.2. Regex
より柔軟で強力なタイプのクエリは正規表現です。 このc` ++ `は、このフィールドのこの正規表現に適したすべてのレコードを返すMongoDB$regexを使用して基準を作成します。
これはstartingWith, endingWith操作と同様に機能します–例を見てみましょう。
現在、Aで始まる名前を持つすべてのユーザーを探しています。
データベースの状態は次のとおりです。
[
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.example.model.User",
"name" : "Eric",
"age" : 45
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581908"),
"_class" : "org.example.model.User",
"name" : "Antony",
"age" : 33
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581909"),
"_class" : "org.example.model.User",
"name" : "Alice",
"age" : 35
}
]
クエリを作成しましょう:
Query query = new Query();
query.addCriteria(Criteria.where("name").regex("^A"));
List users = mongoTemplate.find(query,User.class);
これが実行され、2つのレコードが返されます。
[
{
"_id" : ObjectId("55c0e5e5511f0a164a581908"),
"_class" : "org.example.model.User",
"name" : "Antony",
"age" : 33
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581909"),
"_class" : "org.example.model.User",
"name" : "Alice",
"age" : 35
}
]
別の簡単な例を次に示します。今回は、名前がcで終わるすべてのユーザーを探します。
Query query = new Query();
query.addCriteria(Criteria.where("name").regex("c$"));
List users = mongoTemplate.find(query, User.class);
結果は次のようになります。
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.example.model.User",
"name" : "Eric",
"age" : 45
}
2.3. Ltおよびgt
これらの演算子は、$lt(より小さい)演算子と$gt(より大きい)を使用して基準を作成します。
例を簡単に見てみましょう。20〜50歳のすべてのユーザーを探しています。
データベースは次のとおりです。
[
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.example.model.User",
"name" : "Eric",
"age" : 45
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581908"),
"_class" : "org.example.model.User",
"name" : "Antony",
"age" : 55
}
}
このクエリコード:
Query query = new Query();
query.addCriteria(Criteria.where("age").lt(50).gt(20));
List users = mongoTemplate.find(query,User.class);
その結果、20歳以上50歳未満のすべてのユーザー:
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.example.model.User",
"name" : "Eric",
"age" : 45
}
2.4. Sort
Sortは、結果の並べ替え順序を指定するために使用されます。
以下の例は、年齢で昇順にソートされたすべてのユーザーを返します。
まず、既存のデータは次のとおりです。
[
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.example.model.User",
"name" : "Eric",
"age" : 45
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581908"),
"_class" : "org.example.model.User",
"name" : "Antony",
"age" : 33
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581909"),
"_class" : "org.example.model.User",
"name" : "Alice",
"age" : 35
}
]
sortを実行した後:
Query query = new Query();
query.with(new Sort(Sort.Direction.ASC, "age"));
List users = mongoTemplate.find(query,User.class);
そして、これがクエリの結果です–ageでうまくソートされています:
[
{
"_id" : ObjectId("55c0e5e5511f0a164a581908"),
"_class" : "org.example.model.User",
"name" : "Antony",
"age" : 33
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581909"),
"_class" : "org.example.model.User",
"name" : "Alice",
"age" : 35
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.example.model.User",
"name" : "Eric",
"age" : 45
}
]
2.5. Pageable
ページネーションを使用した簡単な例を見てみましょう。
データベースの状態は次のとおりです。
[
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.example.model.User",
"name" : "Eric",
"age" : 45
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581908"),
"_class" : "org.example.model.User",
"name" : "Antony",
"age" : 33
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581909"),
"_class" : "org.example.model.User",
"name" : "Alice",
"age" : 35
}
]
ここで、単純にサイズ2のページを要求するクエリロジック:
final Pageable pageableRequest = PageRequest.of(0, 2);
Query query = new Query();
query.with(pageableRequest);
そして結果-予想通りの2つのドキュメント:
[
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.example.model.User",
"name" : "Eric",
"age" : 45
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581908"),
"_class" : "org.example.model.User",
"name" : "Antony",
"age" : 33
}
]
3. 生成されたクエリメソッド
ここで、Spring Dataが通常提供するより一般的なタイプのクエリ、つまりメソッド名から自動生成されたクエリについて見ていきましょう。
これらの種類のクエリを活用するために必要なことは、リポジトリインターフェースでメソッドを宣言することだけです。
public interface UserRepository
extends MongoRepository, QueryDslPredicateExecutor {
...
}
3.1. FindByX
まず、findByタイプのクエリを調べることから始めます。この場合は、名前で検索します:__
List findByName(String name);
前のセクションと同じ-2.1-クエリは同じ結果になり、指定された名前を持つすべてのユーザーを検索します。
List users = userRepository.findByName("Eric");
3.2. StartingWithおよび エンディングウィズ。
2.2では、regexベースのクエリを検討しました。 もちろん、最初と最後はそれほど強力ではありませんが、それでも、特に実際に実装する必要がない場合は、非常に便利です。
操作がどのように見えるかの簡単な例を次に示します。__
List findByNameStartingWith(String regexp);
List findByNameEndingWith(String regexp);
もちろん、実際にこれを使用する例は非常に簡単です。
List users = userRepository.findByNameStartingWith("A");
List users = userRepository.findByNameEndingWith("c");
そして、結果はまったく同じです。
3.3. Between
2.3と同様に、これはageGTからageLT:の間の年齢のすべてのユーザーを返します
List findByAgeBetween(int ageGT, int ageLT);
メソッドを呼び出すと、まったく同じドキュメントが見つかります。
List users = userRepository.findByAgeBetween(20, 50);
3.4. LikeおよびOrderBy
今回は、生成されたクエリに2種類の修飾子を組み合わせた、より高度な例を見てみましょう。
文字Aを含む名前を持つすべてのユーザーを検索し、結果を年齢順に昇順で並べ替えます。
List users = userRepository.findByNameLikeOrderByAgeAsc("A");
2.4で使用したデータベースの場合、結果は次のようになります。
[
{
"_id" : ObjectId("55c0e5e5511f0a164a581908"),
"_class" : "org.example.model.User",
"name" : "Antony",
"age" : 33
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581909"),
"_class" : "org.example.model.User",
"name" : "Alice",
"age" : 35
}
]
4. JSONクエリメソッド
メソッド名または条件を使用してクエリを表すことができない場合は、より低レベルのuse the @Query annotationを実行できます。
この注釈を使用して、生のクエリをMongo JSONクエリ文字列として指定できます。
4.1. FindBy
簡単に始めて、最初にa find by type of methodをどのように表すかを見てみましょう。
@Query("{ 'name' : ?0 }")
List findUsersByName(String name);
このメソッドは、名前でユーザーを返す必要があります。プレースホルダー?0は、メソッドの最初のパラメーターを参照します。
List users = userRepository.findUsersByName("Eric");
4.2 $regex
a regex driven queryも見てみましょう。もちろん、2.2および3.2と同じ結果が得られます。
@Query("{ 'name' : { $regex: ?0 } }")
List findUsersByRegexpName(String regexp);
使用方法もまったく同じです。
List users = userRepository.findUsersByRegexpName("^A");
List users = userRepository.findUsersByRegexpName("c$");
4.3. $ltおよび$gt
次に、ltクエリとgtクエリを実装しましょう。
@Query("{ 'age' : { $gt: ?0, $lt: ?1 } }")
List findUsersByAgeBetween(int ageGT, int ageLT);
メソッドに2つのパラメーターがあるので、生のクエリでこれらの各パラメーターをインデックスで参照します:?0と?1。
List users = userRepository.findUsersByAgeBetween(20, 50);
5. QueryDSLクエリ
MongoRepositoryはQueryDSLプロジェクトを適切にサポートしているため、ここでもその優れたタイプセーフAPIを活用できます。
5.1. Mavenの依存関係
まず、pomで正しいMaven依存関係が定義されていることを確認しましょう。
com.mysema.querydsl
querydsl-mongodb
3.6.6
com.mysema.querydsl
querydsl-apt
3.6.6
5.2. Q-クラス
QueryDSLは、クエリの作成にQクラスを使用しました。 ただし、これらを手動で作成する必要はあまりないため、we need to generate themはどういうわけかです。
これを行うには、apt-maven-pluginを使用します。
com.mysema.maven
apt-maven-plugin
1.1.3
process
target/generated-sources/java
org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor
Userクラスを見てみましょう–特に@QueryEntityアノテーションに焦点を当てます。
@QueryEntity
@Document
public class User {
@Id
private String id;
private String name;
private Integer age;
// standard getters and setters
}
Mavenライフサイクルのprocessゴール(またはその後の別のゴール)を実行した後–target/generated-sources/java/\{your package structure}の下のaptプラグインwill generate the new classes:
/**
* QUser is a Querydsl query type for User
*/
@Generated("com.mysema.query.codegen.EntitySerializer")
public class QUser extends EntityPathBase {
private static final long serialVersionUID = ...;
public static final QUser user = new QUser("user");
public final NumberPath age = createNumber("age", Integer.class);
public final StringPath id = createString("id");
public final StringPath name = createString("name");
public QUser(String variable) {
super(User.class, forVariable(variable));
}
public QUser(Path path) {
super(path.getType(), path.getMetadata());
}
public QUser(PathMetadata metadata) {
super(User.class, metadata);
}
}
このクラスの助けを借りて、クエリを作成することはありません。
補足として– Eclipseを使用している場合、このプラグインを導入すると、pomで次の警告が生成されます。
JDKを使用してビルドを実行するか、クラスパスにtools.jarを設定する必要があります。 Eclipseのビルド中にこれが発生した場合は、JDKでもEclipseを実行してください(com.mysema.maven:apt-maven-plugin:1.1.3:process:default:generate-sources
Maveninstallは正常に動作し、QUserクラスが生成されますが、プラグインはpomで強調表示されます。
簡単な修正は、eclipse.iniでJDKを手動で指すことです。
...
-vm
{path_to_jdk}\jdk{your_version}\bin\javaw.exe
5.3. The New Repository
次に、リポジトリでQueryDSLサポートを実際に有効にする必要があります。これは単にextending the QueryDslPredicateExecutor interfaceによって実行されます。
public interface UserRepository extends
MongoRepository, QuerydslPredicateExecutor
5.4. Eq
サポートを有効にすると、前に説明したようにlet’s now implement the same queriesになります。
単純な平等から始めましょう。
QUser qUser = new QUser("user");
Predicate predicate = qUser.name.eq("Eric");
List users = (List) userRepository.findAll(predicate);
5.5. StartingWithおよびEndingWith
同様に、前のクエリを実装して、Aで始まる名前のユーザーを見つけましょう。
QUser qUser = new QUser("user");
Predicate predicate = qUser.name.startsWith("A");
List users = (List) userRepository.findAll(predicate);
そしてcで終わる:
QUser qUser = new QUser("user");
Predicate predicate = qUser.name.endsWith("c");
List users = (List) userRepository.findAll(predicate);
2.2、3.2、または4.2と同じ結果。
5.6. Between
次の1つのクエリは、前のセクションと同様に、20〜50歳のユーザーを返します。
QUser qUser = new QUser("user");
Predicate predicate = qUser.age.between(20, 50);
List users = (List) userRepository.findAll(predicate);
6. 結論
この記事では、Spring Data MongoDBを使用してクエリを実行できる多くの方法を検討しました。
一歩下がって、MongoDBにクエリを実行するために必要な強力な方法がいくつあるかを確認するのは興味深いことです。制限された制御から、生のクエリによる完全な制御までさまざまです。
これらすべての例とコードスニペットcan be found inthe GitHub projectの実装–これはEclipseベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。