1. 概要

このチュートリアルでは、Spring DataMongoDBでさまざまなタイプのクエリを構築することに焦点を当てます。

QueryおよびCriteriaクラス、自動生成されたクエリメソッド、JSONクエリ、およびQueryDSLを使用したドキュメントのクエリについて説明します。

Mavenのセットアップについては、紹介記事をご覧ください。

2. ドキュメントクエリ

Spring Dataを使用してMongoDBをクエリする最も一般的な方法の1つは、ネイティブ演算子を非常に厳密に反映するQueryクラスとCriteriaクラスを使用することです。

2.1. Is

これは単に平等を使用する基準です。 それがどのように機能するか見てみましょう。

次の例では、Ericという名前のユーザーを探します。

私たちのデータベースを見てみましょう:

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581907"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eric",
        "age" : 45
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 55
    }
}

次に、クエリコードを見てみましょう。

Query query = new Query();
query.addCriteria(Criteria.where("name").is("Eric"));
List<User> users = mongoTemplate.find(query, User.class);

予想どおり、このロジックは次を返します。

{
    "_id" : ObjectId("55c0e5e5511f0a164a581907"),
    "_class" : "org.baeldung.model.User",
    "name" : "Eric",
    "age" : 45
}

2.2. 正規表現

より柔軟で強力なタイプのクエリは正規表現です。 これにより、MongoDB $ regex を使用して基準が作成され、このフィールドの正規表現に適したすべてのレコードが返されます。

startingWithおよびendingWith操作と同様に機能します。

この例では、Aで始まる名前を持つすべてのユーザーを検索します。

データベースの状態は次のとおりです。

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581907"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eric",
        "age" : 45
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 33
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581909"),
        "_class" : "org.baeldung.model.User",
        "name" : "Alice",
        "age" : 35
    }
]

次に、クエリを作成しましょう。

Query query = new Query();
query.addCriteria(Criteria.where("name").regex("^A"));
List<User> users = mongoTemplate.find(query,User.class);

これが実行され、2つのレコードが返されます。

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 33
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581909"),
        "_class" : "org.baeldung.model.User",
        "name" : "Alice",
        "age" : 35
    }
]

別の簡単な例を次に示します。今回は、名前がcで終わるすべてのユーザーを探します。

Query query = new Query();
query.addCriteria(Criteria.where("name").regex("c$"));
List<User> users = mongoTemplate.find(query, User.class);

したがって、結果は次のようになります。

{
    "_id" : ObjectId("55c0e5e5511f0a164a581907"),
    "_class" : "org.baeldung.model.User",
    "name" : "Eric",
    "age" : 45
}

2.3. Ltおよびgt

これらの演算子は、 $ lt (より小さい)および $ gt (より大きい)演算子を使用して基準を作成します。

20歳から50歳までのすべてのユーザーを探している簡単な例を見てみましょう。

データベースは次のとおりです。

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581907"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eric",
        "age" : 45
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 55
    }
}

クエリコード:

Query query = new Query();
query.addCriteria(Criteria.where("age").lt(50).gt(20));
List<User> users = mongoTemplate.find(query,User.class);

そして、20歳以上50歳未満のすべてのユーザーの結果:

{
    "_id" : ObjectId("55c0e5e5511f0a164a581907"),
    "_class" : "org.baeldung.model.User",
    "name" : "Eric",
    "age" : 45
}

2.4。並べ替え

Sort は、結果の並べ替え順序を指定するために使用されます。

次の例では、年齢別に昇順で並べ替えられたすべてのユーザーが返されます。

まず、既存のデータは次のとおりです。

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581907"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eric",
        "age" : 45
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 33
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581909"),
        "_class" : "org.baeldung.model.User",
        "name" : "Alice",
        "age" : 35
    }
]

sort を実行した後:

Query query = new Query();
query.with(Sort.by(Sort.Direction.ASC, "age"));
List<User> users = mongoTemplate.find(query,User.class);

そして、これがクエリの結果であり、ageで適切にソートされています。

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 33
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581909"),
        "_class" : "org.baeldung.model.User",
        "name" : "Alice",
        "age" : 35
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581907"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eric",
        "age" : 45
    }
]

2.5。ページ可能

ページネーションを使用した簡単な例を見てみましょう。

データベースの状態は次のとおりです。

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581907"),
        "_class" : "org.baeldung.model.User",
        "name" : "Eric",
        "age" : 45
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 33
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581909"),
        "_class" : "org.baeldung.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.baeldung.model.User",
        "name" : "Eric",
        "age" : 45
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 33
    }
]

3. 生成されたクエリメソッド

次に、Spring Dataが通常提供する、より一般的なタイプのクエリ、メソッド名から自動生成されたクエリについて見ていきましょう。

これらの種類のクエリを活用するために必要なのは、リポジトリインターフェイスでメソッドを宣言することだけです。

public interface UserRepository 
  extends MongoRepository<User, String>, QueryDslPredicateExecutor<User> {
    ...
}

3.1. FindByX

findByタイプのクエリを調べることから、簡単に始めましょう。 この場合、名前で検索を使用します:

List<User> findByName(String name);

前のセクション2.1と同様に、クエリの結果は同じで、指定された名前のすべてのユーザーが検索されます。

List<User> users = userRepository.findByName("Eric");

3.2. StartingWithおよびendingWith

セクション2.2では、regexベースのクエリについて説明しました。 もちろん、最初と最後はそれほど強力ではありませんが、それでも、特に実際に実装する必要がない場合は、非常に便利です。

操作がどのようになるかの簡単な例を次に示します。

List<User> findByNameStartingWith(String regexp);
List<User> findByNameEndingWith(String regexp);

もちろん、これを実際に使用する例は非常に簡単です。

List<User> users = userRepository.findByNameStartingWith("A");
List<User> users = userRepository.findByNameEndingWith("c");

そして、結果はまったく同じです。

3.3.

セクション2.3と同様に、これは ageGTageLTの間の年齢のすべてのユーザーを返します:

List<User> findByAgeBetween(int ageGT, int ageLT);

メソッドを呼び出すと、まったく同じドキュメントが見つかります。

List<User> users = userRepository.findByAgeBetween(20, 50);

3.4. LikeおよびOrderBy

今回は、生成されたクエリに2種類の修飾子を組み合わせた、より高度な例を見てみましょう。

A、の文字を含む名前を持つすべてのユーザーを検索し、結果を年齢順に昇順で並べ替えます。

List<User> users = userRepository.findByNameLikeOrderByAgeAsc("A");

セクション2.4で使用したデータベースの場合、結果は次のようになります。

[
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.baeldung.model.User",
        "name" : "Antony",
        "age" : 33
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581909"),
        "_class" : "org.baeldung.model.User",
        "name" : "Alice",
        "age" : 35
    }
]

4. JSONクエリメソッド

メソッド名または条件を使用してクエリを表現できない場合は、より低レベルの処理を実行できます。@Queryアノテーションを使用します。

このアノテーションを使用すると、生のクエリをMongoJSONクエリ文字列として指定できます。

4.1. FindBy

簡単に始めて、最初にメソッドのタイプによる検索をどのように表すかを見てみましょう。

@Query("{ 'name' : ?0 }")
List<User> findUsersByName(String name);

このメソッドは、ユーザーを名前で返す必要があります。 プレースホルダー?0 は、メソッドの最初のパラメーターを参照します。

List<User> users = userRepository.findUsersByName("Eric");

4.2. $ regex

正規表現駆動型クエリも確認できます。もちろん、セクション2.2および3.2と同じ結果が得られます。

@Query("{ 'name' : { $regex: ?0 } }")
List<User> findUsersByRegexpName(String regexp);

使用法もまったく同じです。

List<User> users = userRepository.findUsersByRegexpName("^A");
List<User> users = userRepository.findUsersByRegexpName("c$");

4.3. $ltおよび$gt

次に、ltおよびgtクエリを実装しましょう。

@Query("{ 'age' : { $gt: ?0, $lt: ?1 } }")
List<User> findUsersByAgeBetween(int ageGT, int ageLT);

メソッドに2つのパラメーターがあるので、生のクエリ?0 ?1:のインデックスでそれぞれを参照しています。

List<User> users = userRepository.findUsersByAgeBetween(20, 50);

5. QueryDSLクエリ

MongoRepositoryQueryDSLプロジェクトを適切にサポートしているため、ここでもその優れたタイプセーフAPIを活用できます。

5.1. Mavenの依存関係

まず、pomで正しいMaven依存関係が定義されていることを確認しましょう。

<dependency>
    <groupId>com.mysema.querydsl</groupId>
    <artifactId>querydsl-mongodb</artifactId>
    <version>4.3.1</version>
</dependency>
<dependency>
    <groupId>com.mysema.querydsl</groupId>
    <artifactId>querydsl-apt</artifactId>
    <version>4.3.1</version>
</dependency>

5.2。Q-クラス

QueryDSLはクエリの作成にQクラスを使用しましたが、実際には手動で作成したくないので、何らかの方法でそれらを生成する必要があります

これを行うには、apt-maven-pluginを使用します。

<plugin>    
    <groupId>com.mysema.maven</groupId>
    <artifactId>apt-maven-plugin</artifactId>
    <version>1.1.3</version>
    <executions>
        <execution>
            <goals>
                <goal>process</goal>
            </goals>
            <configuration>
                <outputDirectory>target/generated-sources/java</outputDirectory>
                <processor>
                  org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor
                </processor>
            </configuration>
        </execution>
     </executions>
</plugin>

User クラスを見てみましょう。特に、@QueryEntityアノテーションに焦点を当てています。

@QueryEntity 
@Document
public class User {
 
    @Id
    private String id;
    private String name;
    private Integer age;
 
    // standard getters and setters
}

Mavenライフサイクルのプロセスゴール(またはその後のその他のゴール)を実行した後、aptプラグイン target /generated-sources/javaの下に新しいクラスを生成します/{パッケージ構造}:

/**
 * QUser is a Querydsl query type for User
 */
@Generated("com.mysema.query.codegen.EntitySerializer")
public class QUser extends EntityPathBase<User> {

    private static final long serialVersionUID = ...;

    public static final QUser user = new QUser("user");

    public final NumberPath<Integer> 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<? extends User> 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

Maven install は正常に動作し、 QUser クラスが生成されますが、プラグインはpomで強調表示されます。

簡単な修正は、eclipse.iniでJDKを手動でポイントすることです。

...
-vm
{path_to_jdk}\jdk{your_version}\bin\javaw.exe

5.3. 新しいリポジトリ

次に、リポジトリでQueryDSLサポートを実際に有効にする必要があります。これは、QueryDslPredicateExecutorインターフェイス拡張するだけで実行できます。

public interface UserRepository extends 
  MongoRepository<User, String>, QuerydslPredicateExecutor<User>

5.4. Eq

サポートを有効にして、前に示したものと同じクエリを実装しましょう。

単純な平等から始めましょう。

QUser qUser = new QUser("user");
Predicate predicate = qUser.name.eq("Eric");
List<User> users = (List<User>) userRepository.findAll(predicate);

5.5. StartingWithおよびEndingWith

同様に、前のクエリを実装して、Aで始まる名前のユーザーを見つけましょう。

QUser qUser = new QUser("user");
Predicate predicate = qUser.name.startsWith("A");
List<User> users = (List<User>) userRepository.findAll(predicate);

c で終わるだけでなく:

QUser qUser = new QUser("user");
Predicate predicate = qUser.name.endsWith("c");
List<User> users = (List<User>) userRepository.findAll(predicate);

結果はセクション2.2、3.2、4.2と同じです。

5.6.

次のクエリは、前のセクションと同様に、20〜50歳のユーザーを返します。

QUser qUser = new QUser("user");
Predicate predicate = qUser.age.between(20, 50);
List<User> users = (List<User>) userRepository.findAll(predicate);

6. 結論

この記事では、SpringDataMongoDBを使用してクエリを実行できるさまざまな方法について説明しました。

一歩下がって、MongoDBにクエリを実行するために必要なすべての強力な方法を確認するのは興味深いことです。制限された制御から、生のクエリによる完全な制御までさまざまです。

これらすべての例とコードスニペットの実装は、GitHubプロジェクトにあります。