MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Una guida alle query in Spring Data MongoDB

1. Panoramica

Questo tutorial si concentrerà sulla creazione di diversi tipi di query in Spring Data MongoDB .

Esamineremo la query sui documenti con Query e Criteri classi, metodi di query generati automaticamente, query JSON e QueryDSL.

Per la configurazione di Maven, dai un'occhiata al nostro articolo introduttivo.

2. Query sui documenti

Uno dei modi più comuni per interrogare MongoDB con Spring Data è utilizzare la Query e Criteri classi, che rispecchiano molto da vicino gli operatori nativi.

2.1. È

Questo è semplicemente un criterio che utilizza l'uguaglianza. Vediamo come funziona.

Nell'esempio seguente, cercheremo utenti denominati Eric .

Diamo un'occhiata al nostro database:

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

Ora diamo un'occhiata al codice della query:

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

Come previsto, questa logica restituisce:

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

2.2. Regex

Un tipo di query più flessibile e potente è la regex. Questo crea un criterio usando un MongoDB $regex che restituisce tutti i record adatti alla regex per questo campo.

Funziona in modo simile a startingWith e che termina con operazioni.

In questo esempio, cercheremo tutti gli utenti che hanno nomi che iniziano con A .

Ecco lo stato del database:

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

Ora creiamo la query:

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

Questo viene eseguito e restituisce 2 record:

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

Ecco un altro rapido esempio, questa volta cercando tutti gli utenti che hanno nomi che terminano con c :

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

Quindi il risultato sarà:

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

2.3. Tenente e gt

Questi operatori creano un criterio utilizzando $lt (minore di) e $gt (maggiore di) operatori.

Facciamo un rapido esempio in cui stiamo cercando tutti gli utenti di età compresa tra 20 e 50 anni.

Il database è:

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

Il codice della query:

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

E i risultati per tutti gli utenti di età superiore a 20 anni e inferiore a 50:

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

2.4. Ordina

Ordina viene utilizzato per specificare un ordinamento per i risultati.

L'esempio seguente restituisce tutti gli utenti ordinati per età in ordine crescente.

Innanzitutto, ecco i dati esistenti:

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

Dopo aver eseguito ordina :

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

Ed ecco il risultato della query, ben ordinato per età :

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

Diamo un'occhiata a un rapido esempio di utilizzo dell'impaginazione.

Ecco lo stato del database:

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

Ora ecco la logica della query, semplicemente chiedendo una pagina di dimensione 2:

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

E il risultato, i 2 documenti, come previsto:

[
    {
        "_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. Metodi di query generati

Ora esploriamo il tipo più comune di query che Spring Data fornisce solitamente, query generate automaticamente dai nomi dei metodi.

L'unica cosa che dobbiamo fare per sfruttare questo tipo di query è dichiarare il metodo sull'interfaccia del repository:

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

3.1. FindByX

Inizieremo in modo semplice, esplorando il tipo di query findBy. In questo caso, utilizzeremo trova per nome:

List<User> findByName(String name);

Proprio come nella sezione precedente, 2.1, la query avrà gli stessi risultati, trovando tutti gli utenti con il nome dato:

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

3.2. A partire da e che termina con

Nella sezione 2.2, abbiamo esplorato una regex interrogazione basata. L'inizio e la fine sono ovviamente meno potenti, ma comunque abbastanza utili, soprattutto se non dobbiamo implementarli effettivamente.

Ecco un rapido esempio di come sarebbero le operazioni:

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

L'esempio dell'utilizzo effettivo di questo sarebbe, ovviamente, molto semplice:

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

E i risultati sono esattamente gli stessi.

3.3. Tra

Simile alla sezione 2.3, questo restituirà tutti gli utenti con età compresa tra ageGT e etàLT:

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

Chiamando il metodo verranno trovati esattamente gli stessi documenti:

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

3.4. Mi piace e Ordina per

Diamo un'occhiata a un esempio più avanzato questa volta, combinando due tipi di modificatori per la query generata.

Cercheremo tutti gli utenti che hanno nomi contenenti la lettera A e ordineremo anche i risultati per età, in ordine crescente:

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

Per il database utilizzato nella sezione 2.4, il risultato sarà:

[
    {
        "_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. Metodi di query JSON

Se non possiamo rappresentare una query con l'aiuto del nome di un metodo o dei criteri, possiamo fare qualcosa di più basso, usare @Query annotazione .

Con questa annotazione, possiamo specificare una query grezza come stringa di query JSON Mongo.

4.1. Trova per

Iniziamo in modo semplice e vediamo come rappresenteremmo un trova di tipo di metodo primo:

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

Questo metodo dovrebbe restituire gli utenti per nome. Il segnaposto ?0 fa riferimento al primo parametro del metodo.

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

4.2. $regex

Possiamo anche esaminare una query basata su espressioni regolari che ovviamente produce lo stesso risultato delle sezioni 2.2 e 3.2:

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

Anche l'utilizzo è esattamente lo stesso:

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

4.3. $lt e $gt

Ora implementiamo lt e gt domanda:

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

Ora che il metodo ha 2 parametri, ci riferiamo a ciascuno di questi in base all'indice nella query grezza, ?0 e ?1:

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

5. Query DSL

MongoRepository ha un buon supporto per il progetto QueryDSL, quindi possiamo sfruttare quella bella API type-safe anche qui.

5.1. Le dipendenze di Maven

Innanzitutto, assicuriamoci di avere le dipendenze Maven corrette definite nel 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. D -classi

QueryDSL ha utilizzato le classi Q per creare query, ma poiché non vogliamo crearle a mano, dobbiamo generarle in qualche modo.

Utilizzeremo il plugin apt-maven per farlo:

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

Diamo un'occhiata all'Utente classe, concentrandosi in particolare su @QueryEntity annotazione:

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

Dopo aver eseguito il processo obiettivo del ciclo di vita di Maven (o qualsiasi altro obiettivo successivo a quello), il plug-in apt genererà le nuove classi in target/generated-sources/java/{la tua struttura del pacchetto} :

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

È grazie a questa classe che non abbiamo bisogno di creare le nostre query.

Come nota a margine, se stiamo usando Eclipse, l'introduzione di questo plugin genererà il seguente avviso in pom:

L'installazione di Maven funziona bene e il QUser viene generata la classe, ma un plugin è evidenziato nel pom.

Una soluzione rapida consiste nel puntare manualmente al JDK in eclipse.ini :

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

5.3. Il nuovo repository

Ora dobbiamo effettivamente abilitare il supporto QueryDSL nei nostri repository, cosa che viene eseguita semplicemente estendendo QueryDslPredicateExecutor interfaccia :

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

5.4. Eq

Con il supporto abilitato, ora implementiamo le stesse query come quelli che abbiamo illustrato prima.

Inizieremo con una semplice uguaglianza:

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

5.5. A partire da e EndingWith

Allo stesso modo, implementiamo le query precedenti e troviamo utenti con nomi che iniziano con A :

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

Oltre a terminare con c :

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

Il risultato è lo stesso delle sezioni 2.2, 3.2 e 4.2.

5.6. Tra

La query successiva restituirà utenti di età compresa tra 20 e 50 anni, in modo simile alle sezioni precedenti:

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