Guide des requêtes dans Spring Data MongoDB

Guide des requêtes dans Spring Data MongoDB

1. Vue d'ensemble

Cet article se concentrera sur la construction de différentstypes of queries in Spring Data MongoDB.

Nous allons examiner l'interrogation de documents avec les classesQuery etCriteria, les méthodes de requête générées automatiquement, les requêtes JSON et QueryDSL.

Pour la configuration de Maven, jetez un œil à nosintroductory article.

2. Requête de documents

L'un des moyens les plus courants d'interroger MongoDB avec Spring Data consiste à utiliser les classesQuery etCriteria - qui reflètent très étroitement les opérateurs natifs.

2.1. Is

Il s’agit simplement d’un critère utilisant l’égalité - voyons comment cela fonctionne.

Dans l'exemple suivant, nous recherchons des utilisateurs nommésEric.

Regardons notre base de données:

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

Examinons maintenant le code de requête:

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

Cette logique renvoie, comme prévu:

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

2.2. Regex

La regex est un type de requête plus souple et plus puissant. Ce c` ++ `recrée un critère en utilisant un MongoDB$regex qui renvoie tous les enregistrements appropriés pour cette expression rationnelle pour ce champ.

Cela fonctionne de manière similaire aux opérationsstartingWith, endingWith - prenons un exemple.

Nous recherchons désormais tous les utilisateurs dont le nom commence parA.

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

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

Créons maintenant la requête:

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

Ceci exécute et renvoie 2 enregistrements:

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

Voici un autre exemple rapide, cette fois à la recherche de tous les utilisateurs dont le nom se termine parc:

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

Donc, le résultat sera:

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

2.3. Lt etgt

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

Jetons un coup d'œil à un exemple: nous recherchons tous les utilisateurs âgés de 20 à 50 ans.

La base de données est:

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

Ce code de requête:

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

Et le résultat - tous les utilisateurs qui ont plus de 20 ans et moins de 50 ans:

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

2.4. Sort

Sort 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 en ordre croissant.

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

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

Après avoir exécutésort:

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

Et voici le résultat de la requête - bien trié parage:

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

Prenons un exemple rapide d’utilisation de la pagination.

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

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

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.example.model.User",
        "name" : "Eric",
        "age" : 45
    },
    {
        "_id" : ObjectId("55c0e5e5511f0a164a581908"),
        "_class" : "org.example.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 fourni par Spring Data: les requêtes générées automatiquement à partir des noms de méthode.

La seule chose à faire pour exploiter ce type de requête consiste à déclarer la méthode sur l'interface du référentiel:

public interface UserRepository
  extends MongoRepository, QueryDslPredicateExecutor {
    ...
}

3.1. FindByX

Nous allons commencer simplement en explorant le type de requête findBy - dans ce cas, rechercher par nom: __

List findByName(String name);

Comme dans la section précédente - 2.1 - la requête aura les mêmes résultats et trouvera tous les utilisateurs portant le même nom:

List users = userRepository.findByName("Eric");

3.2. StartingWith et se terminant avec.

Dans la version 2.2, nous avons exploré une requête basée surregex. Les débuts et les fins par sont bien sûr moins puissants, mais néanmoins assez utiles - surtout si nous n’avons pas à les implémenter.

Voici un exemple rapide de l'apparence des opérations: __

List findByNameStartingWith(String regexp);
List findByNameEndingWith(String regexp);

L’exemple de cette utilisation serait bien entendu très simple:

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

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

3.3. Between

Similaire à 2.3, cela renverra tous les utilisateurs avec un âge compris entreageGT etageLT:

List findByAgeBetween(int ageGT, int ageLT);

L'appel de la méthode aura pour résultat que les mêmes documents seront trouvés:

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

3.4. Like etOrderBy

Examinons 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 lettreA et nous allons également classer les résultats par âge, par ordre croissant:

List users = userRepository.findByNameLikeOrderByAgeAsc("A");

Pour la base de données utilisée en 2.4, le résultat sera:

[
    {
        "_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. 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 -use the @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. FindBy

Commençons simplement et voyons comment nous représenterions d'aborda find by type of method:

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

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

List users = userRepository.findUsersByName("Eric");

4.2 $regex

Regardons aussia regex driven query - qui produit bien sûr le même résultat que dans 2.2 et 3.2:

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

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

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

4.3. $lt et$gt

Implémentons maintenant les requêtes lt etgt:

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

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

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

5. Requêtes Requêtes DSL

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

5.1. Les dépendances Maven

Tout d'abord, vérifions que les dépendances Maven correctes sont définies dans le pom:


    com.mysema.querydsl
    querydsl-mongodb
    3.6.6


    com.mysema.querydsl
    querydsl-apt
    3.6.6

5.2. Qclasses s

QueryDSL a utilisé les classes Q pour créer des requêtes. Mais, puisque nous ne voulons pas vraiment les créer à la main,we need to generate them en quelque sorte.

Nous allons utiliser le plugin apt-maven-plugin pour ce faire:


    com.mysema.maven
    apt-maven-plugin
    1.1.3
    
        
            
                process
            
            
                target/generated-sources/java
                
                  org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor
                
            
        
     

Examinons la classeUser - en nous concentrant spécifiquement sur l'annotation@QueryEntity:

@QueryEntity
@Document
public class User {

    @Id
    private String id;
    private String name;
    private Integer age;

    // standard getters and setters
}

Après avoir exécuté l'objectifprocess du cycle de vie Maven (ou tout autre objectif après celui-là) - le plugin aptwill generate the new classes soustarget/generated-sources/java/\{your package structure}:

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

C’est avec l’aide de ce cours que nous n’allons pas créer nos requêtes.

En passant, si vous utilisez Eclipse, l'introduction de ce plugin générera l'avertissement suivant dans pom:

Vous devez exécuter la compilation avec JDK ou avoir tools.jar sur le chemin de classe. Si cela se produit pendant la construction d'Eclipse, assurez-vous d'exécuter également eclipse sous JDK (com.mysema.maven: apt-maven-plugin: 1.1.3: process: default: generate-sources

Maveninstall fonctionne bien et la classeQUser est générée, mais un plugin est mis en évidence dans le pom.

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

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

5.3. The New Repository

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

public interface UserRepository extends
  MongoRepository, QuerydslPredicateExecutor

5.4. Eq

Avec le support activé,let’s now implement the same queries 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 users = (List) userRepository.findAll(predicate);

5.5. StartingWith etEndingWith

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

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

Et se terminant parc:

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

Le résultat est identique à celui de 2.2, 3.2 ou 4.2.

5.6. Between

La prochaine requête renverra les utilisateurs âgés de 20 à 50 ans - de la même manière que les sections précédentes:

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

6. Conclusion

Dans cet article, nous avons exploré les nombreuses possibilités d'interrogation à l'aide de Spring Data MongoDB.

Il est intéressant de prendre du recul et de voir à quel point nous disposons de nombreuses façons puissantes d'interroger MongoDB - allant du contrôle limité jusqu'au contrôle total avec des requêtes brutes.

L'implémentation de tous ces exemples et extraits de codecan be found inthe GitHub project - il s'agit d'un projet basé sur Eclipse, il devrait donc être facile à importer et à exécuter tel quel.