Una guida alle query in Spring Data MongoDB

1. Panoramica

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

Esamineremo l' esecuzione di query sui documenti con classi Query e Criteria , metodi di query generati automaticamente, query JSON e QueryDSL.

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

2. Interrogazione documenti

Uno dei modi più comuni per eseguire query su MongoDB con Spring Data è utilizzare le classi Query e Criteria , che rispecchiano molto da vicino gli operatori nativi.

2.1. È

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

Nell'esempio seguente, stiamo cercando utenti di nome 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 users = mongoTemplate.find(query, User.class); 

Questa logica ritorna, come previsto:

{ "_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 utilizzando una regex $ MongoDB che restituisce tutti i record adatti a questa regexp per questo campo.

Funziona in modo simile alle operazioni StartingWith, EndWith : diamo un'occhiata a un esempio.

Stiamo cercando 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 } ]

Creiamo ora la query:

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

Questo esegue 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 alla ricerca di tutti gli utenti il ​​cui nome termina con c :

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

Quindi il risultato sarà:

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

2.3. Lt e gt

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

Diamo una rapida occhiata a un esempio: stiamo cercando tutti gli utenti con 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 } }

Questo codice di query:

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

E il risultato - tutti gli utenti che con un'età superiore a 20 e inferiore a 50:

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

2.4. Ordinare

L' ordinamento viene utilizzato per specificare un ordinamento per i risultati.

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

Primo: 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 l' ordinamento :

Query query = new Query(); query.with(Sort.by(Sort.Direction.ASC, "age")); List 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 utilizzando l'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, la logica della query, chiedendo semplicemente 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

Esaminiamo ora il tipo più comune di query fornito di solito da Spring Data: 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, QueryDslPredicateExecutor { ... }

3.1. FindByX

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

List findByName(String name);

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

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

3.2. StartingWith and endingWith.

In 2.2, we explored a regex based query. Starts and ends with are of course less powerful, but nevertheless quite useful – especially if we don't have to actually implement them.

Here's a quick example of how the operations would look like:

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

The example of actually using this would, of course, be very simple:

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

And the results are exactly the same.

3.3. Between

Similar to 2.3, this will return all users with age between ageGT and ageLT:

List findByAgeBetween(int ageGT, int ageLT);

Calling the method will result in exactly the same documents being found:

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

3.4. Like and OrderBy

Let's have a look at a more advanced example this time – combining two types of modifiers for the generated query.

We're going to be looking for all users that have names containing the letter A and we're also going to order the results by age, in ascending order:

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

For the database we used in 2.4 – the result will be:

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

If we can't represent a query with the help of a method name, or criteria, we can do something more low level – use the @Query annotation.

With this annotation, we can specify a raw query – as a Mongo JSON query string.

4.1. FindBy

Let's start simple and look at how we would represent a find by type of method first:

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

This method should return users by name – the placeholder ?0 references the first parameter of the method.

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

4.2 $regex

Let's also look at a regex driven query – which of course produces the same result as in 2.2 and 3.2:

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

The usage is also exactly the same:

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

4.3. $lt and $gt

Let's now implement the lt and gt query:

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

Now how, now that the method has 2 parameters, we're referencing each of these by index in the raw query: ?0 and ?1.

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

5. QueryDSL Queries

MongoRepository has good support for the QueryDSL project – so we can leverage that nice, type-safe API here as well.

5.1. The Maven Dependencies

First, let's make sure we have the correct Maven dependencies defined in the pom:

 com.mysema.querydsl querydsl-mongodb 4.3.1 com.mysema.querydsl querydsl-apt 4.3.1 

5.2. Q-classes

QueryDSL used Q-classes for creating queries. But, since we don't really want to create these by hand, we need to generate them somehow.

We're going to use the apt-maven-plugin to do that:

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

Let's look at the User class – focusing specifically at the @QueryEntity annotation:

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

After running the process goal of the Maven lifecycle (or anything another goal after that one) – the apt plugin will generate the new classes under target/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); } }

It's with the help of this class that we're not going to be creating our queries.

As a side note – if you're using Eclipse, introducing this plugin will generate the following warning in pom:

You need to run build with JDK or have tools.jar on the classpath. If this occurs during eclipse build make sure you run eclipse under JDK as well (com.mysema.maven:apt-maven-plugin:1.1.3:process:default:generate-sources

Maven install works fine and QUser class is generated, but a plugin is highlighted in the pom.

A quick fix is to manually point to the JDK in eclipse.ini:

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

5.3. The New Repository

Now we need to actually enable QueryDSL support in our repositories – which is done by simply extending the QueryDslPredicateExecutor interface:

public interface UserRepository extends MongoRepository, QuerydslPredicateExecutor

5.4. Eq

With support enabled, let's now implement the same queries as the ones we illustrated before.

We'll start with simple equality:

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

5.5. StartingWith and EndingWith

Similarly, let's implement the previous queries – and find users with names that are starting with A:

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

And ending with c:

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

The result with same as in 2.2, 3.2 or 4.2.

5.6. Between

The next one query will return users with age between 20 and 50 – similar to the previous sections:

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

6. Conclusion

In this article, we explored the many ways we can query using Spring Data MongoDB.

It's interesting to take a step back and see just how many powerful ways we have to query MongoDB – varying from limited control all the way to full control with raw queries.

The implementation of all these examples and code snippets can be found in the GitHub project.