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.