MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Guide des requêtes dans Spring Data MongoDB

1. Présentation

Ce didacticiel se concentrera sur la création de différents types de requêtes dans Spring Data MongoDB .

Nous allons examiner l'interrogation de documents avec Query et Critères classes, méthodes de requête générées automatiquement, requêtes JSON et QueryDSL.

Pour la configuration de Maven, consultez notre article d'introduction.

2. Requête de documents

L'une des façons les plus courantes d'interroger MongoDB avec Spring Data consiste à utiliser la Query et Critères classes, qui reflètent très étroitement les opérateurs natifs.

2.1. Est

Il s'agit simplement d'un critère utilisant l'égalité. Voyons comment cela fonctionne.

Dans l'exemple suivant, nous allons rechercher des utilisateurs nommés Eric .

Regardons notre base de données :

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

Examinons maintenant le code de la requête :

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

Comme prévu, cette logique renvoie :

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

2.2. Regex

Un type de requête plus flexible et puissant est le regex. Cela crée un critère en utilisant un MongoDB $regex qui renvoie tous les enregistrements adaptés à la regex pour ce champ.

Cela fonctionne de la même manière que startingWith et se terminant par opérations.

Dans cet exemple, nous allons rechercher tous les utilisateurs dont le nom commence par A .

Voici l'état de la base de données :

[
    {
        "_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
    }
]

Créons maintenant la requête :

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

Cela s'exécute et renvoie 2 enregistrements :

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

Voici un autre exemple rapide, cette fois en recherchant tous les utilisateurs dont le nom se termine par c :

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

Donc le résultat sera :

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

2.3. Lt et gt

Ces opérateurs créent un critère en utilisant le $lt (inférieur à) et $gt opérateurs (supérieur à).

Prenons un exemple rapide où nous recherchons tous les utilisateurs âgés de 20 à 50 ans.

La base de données est :

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

Le code de requête :

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

Et les résultats pour tous les utilisateurs âgés de plus de 20 ans et de moins de 50 ans :

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

2.4. Trier

Trier est utilisé pour spécifier un ordre de tri pour les résultats.

L'exemple ci-dessous renvoie tous les utilisateurs triés par âge dans l'ordre croissant.

Tout d'abord, voici les données existantes :

[
    {
        "_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
    }
]

Après avoir exécuté sort :

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

Et voici le résultat de la requête, joliment trié par âge :

[
    {
        "_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. Pageable

Regardons un exemple rapide utilisant la pagination.

Voici l'état de la base de données :

[
    {
        "_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
    }
]

Voici maintenant la logique de requête, demandant simplement une page de taille 2 :

final Pageable pageableRequest = PageRequest.of(0, 2);
Query query = new Query();
query.with(pageableRequest);

Et le résultat, les 2 documents, comme prévu :

[
    {
        "_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. Méthodes de requête générées

Explorons maintenant le type de requête le plus courant que Spring Data fournit généralement, les requêtes générées automatiquement à partir des noms de méthode.

La seule chose que nous devons faire pour tirer parti de ces types de requêtes est de déclarer la méthode sur l'interface du référentiel :

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

3.1. RechercherParX

Nous allons commencer simplement, en explorant le type de requête findBy. Dans ce cas, nous utiliserons rechercher par nom :

List<User> findByName(String name);

Tout comme dans la section précédente, 2.1, la requête aura les mêmes résultats, trouvant tous les utilisateurs avec le nom donné :

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

3.2. CommencerPar et se terminant par

Dans la section 2.2, nous avons exploré une regex requête basée. Les débuts et les fins avec sont bien sûr moins puissants, mais néanmoins assez utiles, surtout si nous n'avons pas à les implémenter réellement.

Voici un exemple rapide de ce à quoi ressembleraient les opérations :

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

L'exemple d'utilisation réelle de ceci serait, bien sûr, très simple :

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

Et les résultats sont exactement les mêmes.

3.3. Entre

Semblable à la section 2.3, cela renverra tous les utilisateurs dont l'âge est compris entre ageGT et ageLT :

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

L'appel de la méthode entraînera la recherche des mêmes documents :

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

3.4. J'aime et OrderBy

Intéressons-nous cette fois à un exemple plus avancé, combinant deux types de modificateurs pour la requête générée.

Nous allons rechercher tous les utilisateurs dont le nom contient la lettre A, et nous allons également trier les résultats par âge, par ordre croissant :

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

Pour la base de données que nous avons utilisée dans la section 2.4, le résultat sera :

[
    {
        "_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. Méthodes de requête JSON

Si nous ne pouvons pas représenter une requête à l'aide d'un nom de méthode ou de critères, nous pouvons faire quelque chose de plus bas niveau, utiliser le @Query annotation .

Avec cette annotation, nous pouvons spécifier une requête brute en tant que chaîne de requête Mongo JSON.

4.1. Rechercher par

Commençons simplement et regardons comment nous représenterions une recherche par type de méthode d'abord :

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

Cette méthode doit renvoyer les utilisateurs par leur nom. L'espace réservé ?0 fait référence au premier paramètre de la méthode.

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

4.2. $regex

Nous pouvons également examiner une requête basée sur des regex, ce qui produit bien sûr le même résultat que dans les sections 2.2 et 3.2 :

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

L'utilisation est également exactement la même :

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

4.3. $lt et $gt

Maintenant, implémentons le lt et gt requête :

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

Maintenant que la méthode a 2 paramètres, nous référençons chacun d'eux par index dans la requête brute, ?0 et ?1 :

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

5. Requêtes QueryDSL

MongoRepository a un bon support pour le projet QueryDSL, nous pouvons donc également tirer parti de cette belle API de type sécurisé.

5.1. Les dépendances Maven

Tout d'abord, assurons-nous d'avoir les bonnes dépendances Maven définies dans le pom :

<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 -classes

QueryDSL a utilisé des classes Q pour créer des requêtes, mais comme nous ne voulons pas vraiment les créer à la main, nous devons les générer en quelque sorte.

Nous allons utiliser le plugin apt-maven-plugin pour cela :

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

Regardons l'Utilisateur classe, se concentrant spécifiquement sur @QueryEntity annotation :

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

Après avoir exécuté le processus objectif du cycle de vie Maven (ou tout autre objectif après celui-ci), le plugin apt générera les nouvelles classes sous target/generated-sources/java/{votre structure de package} :

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

C'est grâce à cette classe que nous n'avons pas besoin de créer nos requêtes.

En remarque, si nous utilisons Eclipse, l'introduction de ce plugin générera l'avertissement suivant dans pom :

L'installation Maven fonctionne bien et le QUser la classe est générée, mais un plugin est mis en surbrillance dans le pom.

Une solution rapide consiste à pointer manuellement vers le JDK dans eclipse.ini :

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

5.3. Le nouveau référentiel

Nous devons maintenant activer la prise en charge de QueryDSL dans nos référentiels, ce qui se fait simplement en étendant QueryDslPredicateExecutor interface :

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

5.4. Éq

Avec la prise en charge activée, implémentons maintenant les mêmes requêtes comme ceux que nous avons illustrés précédemment.

Nous allons commencer par une simple égalité :

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

5.5. CommencerPar et EndingWith

De même, implémentons les requêtes précédentes et recherchons les utilisateurs dont les noms commencent par A :

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

En plus de se terminer par c :

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

Le résultat est le même que dans les sections 2.2, 3.2 et 4.2.

5.6. Entre

La requête suivante renverra les utilisateurs dont l'âge est compris entre 20 et 50 ans, comme dans les sections précédentes :

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