1. Visão geral
Este tutorial se concentrará na criação de diferentes tipos de consultas no Spring Data MongoDB .
Vamos examinar documentos de consulta com Query e Critérios classes, métodos de consulta gerados automaticamente, consultas JSON e QueryDSL.
Para a configuração do Maven, dê uma olhada em nosso artigo introdutório.
2. Consulta de documentos
Uma das maneiras mais comuns de consultar o MongoDB com Spring Data é fazendo uso do Query e Critérios classes, que espelham muito de perto os operadores nativos.
2.1. É
Este é simplesmente um critério usando igualdade. Vamos ver como isso funciona.
No exemplo a seguir, procuraremos usuários chamados Eric .
Vejamos nosso banco de dados:
[
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.baeldung.model.User",
"name" : "Eric",
"age" : 45
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581908"),
"_class" : "org.baeldung.model.User",
"name" : "Antony",
"age" : 55
}
}
Agora vamos ver o código da consulta:
Query query = new Query();
query.addCriteria(Criteria.where("name").is("Eric"));
List<User> users = mongoTemplate.find(query, User.class);
Como esperado, essa lógica retorna:
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.baeldung.model.User",
"name" : "Eric",
"age" : 45
}
2.2. Regex
Um tipo de consulta mais flexível e poderoso é o regex. Isso cria um critério usando um MongoDB $regex que retorna todos os registros adequados à regex desse campo.
Funciona de forma semelhante a startingWith e terminando com operações.
Neste exemplo, procuraremos todos os usuários cujos nomes comecem com A .
Aqui está o estado do banco de dados:
[
{
"_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
}
]
Agora vamos criar a consulta:
Query query = new Query();
query.addCriteria(Criteria.where("name").regex("^A"));
List<User> users = mongoTemplate.find(query,User.class);
Isso é executado e retorna 2 registros:
[
{
"_id" : ObjectId("55c0e5e5511f0a164a581908"),
"_class" : "org.baeldung.model.User",
"name" : "Antony",
"age" : 33
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581909"),
"_class" : "org.baeldung.model.User",
"name" : "Alice",
"age" : 35
}
]
Aqui está outro exemplo rápido, desta vez procurando por todos os usuários que têm nomes que terminam com c :
Query query = new Query();
query.addCriteria(Criteria.where("name").regex("c$"));
List<User> users = mongoTemplate.find(query, User.class);
Então o resultado será:
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.baeldung.model.User",
"name" : "Eric",
"age" : 45
}
2.3. Lt e gt
Esses operadores criam um critério usando o $lt (menor que) e $gt (maior que) operadores.
Vejamos um exemplo rápido em que procuramos todos os usuários entre 20 e 50 anos.
O banco de dados é:
[
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.baeldung.model.User",
"name" : "Eric",
"age" : 45
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581908"),
"_class" : "org.baeldung.model.User",
"name" : "Antony",
"age" : 55
}
}
O código da consulta:
Query query = new Query();
query.addCriteria(Criteria.where("age").lt(50).gt(20));
List<User> users = mongoTemplate.find(query,User.class);
E os resultados para todos os usuários com idade superior a 20 e inferior a 50:
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.baeldung.model.User",
"name" : "Eric",
"age" : 45
}
2.4. Classificar
Classificar é usado para especificar uma ordem de classificação para os resultados.
O exemplo abaixo retorna todos os usuários classificados por idade em ordem crescente.
Primeiro, aqui estão os dados existentes:
[
{
"_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
}
]
Depois de executar sort :
Query query = new Query();
query.with(Sort.by(Sort.Direction.ASC, "age"));
List<User> users = mongoTemplate.find(query,User.class);
E aqui está o resultado da consulta, bem ordenado por idade :
[
{
"_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. Paginável
Vejamos um exemplo rápido usando paginação.
Aqui está o estado do banco de dados:
[
{
"_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
}
]
Agora aqui está a lógica da consulta, simplesmente pedindo uma página de tamanho 2:
final Pageable pageableRequest = PageRequest.of(0, 2);
Query query = new Query();
query.with(pageableRequest);
E o resultado, os 2 documentos, como esperado:
[
{
"_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étodos de consulta gerados
Agora vamos explorar o tipo mais comum de consulta que o Spring Data geralmente fornece, consultas geradas automaticamente a partir de nomes de métodos.
A única coisa que precisamos fazer para alavancar esses tipos de consultas é declarar o método na interface do repositório:
public interface UserRepository
extends MongoRepository<User, String>, QueryDslPredicateExecutor<User> {
...
}
3.1. FindByX
Começaremos simples, explorando o tipo de consulta findBy. Nesse caso, usaremos localizar por nome:
List<User> findByName(String name);
Assim como na seção anterior, 2.1, a consulta terá os mesmos resultados, encontrando todos os usuários com o nome dado:
List<User> users = userRepository.findByName("Eric");
3.2. Começando com e terminando com
Na seção 2.2, exploramos uma regex consulta baseada. Começar e terminar com são obviamente menos poderosos, mas ainda assim bastante úteis, especialmente se não tivermos que implementá-los de fato.
Veja um exemplo rápido de como seriam as operações:
List<User> findByNameStartingWith(String regexp);
List<User> findByNameEndingWith(String regexp);
O exemplo de realmente usar isso seria, é claro, muito simples:
List<User> users = userRepository.findByNameStartingWith("A");
List<User> users = userRepository.findByNameEndingWith("c");
E os resultados são exatamente os mesmos.
3.3. Entre
Semelhante à seção 2.3, isso retornará todos os usuários com idades entre ageGT e ageLT:
List<User> findByAgeBetween(int ageGT, int ageLT);
Chamar o método resultará exatamente na localização dos mesmos documentos:
List<User> users = userRepository.findByAgeBetween(20, 50);
3.4. Curtir e OrdemPor
Vamos dar uma olhada em um exemplo mais avançado desta vez, combinando dois tipos de modificadores para a consulta gerada.
Procuraremos todos os usuários que tenham nomes contendo a letra A, e também vamos ordenar os resultados por idade, em ordem crescente:
List<User> users = userRepository.findByNameLikeOrderByAgeAsc("A");
Para o banco de dados que usamos na seção 2.4, o resultado será:
[
{
"_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étodos de consulta JSON
Se não pudermos representar uma consulta com a ajuda de um nome de método ou critério, podemos fazer algo de nível mais baixo, usar o @Query anotação .
Com essa anotação, podemos especificar uma consulta bruta como uma string de consulta Mongo JSON.
4.1. Encontrar por
Vamos começar de forma simples e ver como representaríamos um localizar por tipo de método primeiro:
@Query("{ 'name' : ?0 }")
List<User> findUsersByName(String name);
Este método deve retornar os usuários pelo nome. O espaço reservado ?0 referencia o primeiro parâmetro do método.
List<User> users = userRepository.findUsersByName("Eric");
4.2. $regex
Também podemos analisar uma consulta orientada por regex, que obviamente produz o mesmo resultado que nas seções 2.2 e 3.2:
@Query("{ 'name' : { $regex: ?0 } }")
List<User> findUsersByRegexpName(String regexp);
O uso também é exatamente o mesmo:
List<User> users = userRepository.findUsersByRegexpName("^A");
List<User> users = userRepository.findUsersByRegexpName("c$");
4.3. $lt e $gt
Agora vamos implementar o lt e gt inquerir:
@Query("{ 'age' : { $gt: ?0, $lt: ?1 } }")
List<User> findUsersByAgeBetween(int ageGT, int ageLT);
Agora que o método tem 2 parâmetros, estamos referenciando cada um deles por índice na consulta bruta, ?0 e ?1:
List<User> users = userRepository.findUsersByAgeBetween(20, 50);
5. Consultas QueryDSL
MongoRepository tem um bom suporte para o projeto QueryDSL, então podemos aproveitar essa API agradável e segura aqui também.
5.1. As dependências do Maven
Primeiro, vamos ter certeza de que temos as dependências corretas do Maven definidas no 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 usou Q-classes para criar consultas, mas como não queremos criá-las manualmente, precisamos gerá-las de alguma maneira.
Vamos usar o apt-maven-plugin para fazer isso:
<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>
Vejamos o Usuário classe, focando especificamente no @QueryEntity anotação:
@QueryEntity
@Document
public class User {
@Id
private String id;
private String name;
private Integer age;
// standard getters and setters
}
Depois de executar o processo objetivo do ciclo de vida do Maven (ou qualquer outro objetivo após esse), o plugin apt gerará as novas classes em 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<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);
}
}
É por causa dessa classe que não precisamos criar nossas consultas.
Como observação lateral, se estivermos usando o Eclipse, a introdução deste plug-in gerará o seguinte aviso no pom:
A instalação do Maven funciona bem e o QUser classe é gerada, mas um plugin é destacado no pom.
Uma solução rápida é apontar manualmente para o JDK em eclipse.ini :
...
-vm
{path_to_jdk}\jdk{your_version}\bin\javaw.exe
5.3. O novo repositório
Agora precisamos realmente habilitar o suporte QueryDSL em nossos repositórios, o que é feito simplesmente estendendo o QueryDslPredicateExecutor interface :
public interface UserRepository extends
MongoRepository<User, String>, QuerydslPredicateExecutor<User>
5.4. Eq
Com o suporte ativado, vamos agora implementar as mesmas consultas como os que ilustramos antes.
Vamos começar com igualdade simples:
QUser qUser = new QUser("user");
Predicate predicate = qUser.name.eq("Eric");
List<User> users = (List<User>) userRepository.findAll(predicate);
5.5. Começando com e Terminar com
Da mesma forma, vamos implementar as consultas anteriores e encontrar usuários com nomes que começam com A :
QUser qUser = new QUser("user");
Predicate predicate = qUser.name.startsWith("A");
List<User> users = (List<User>) userRepository.findAll(predicate);
Além de terminar com c :
QUser qUser = new QUser("user");
Predicate predicate = qUser.name.endsWith("c");
List<User> users = (List<User>) userRepository.findAll(predicate);
O resultado é o mesmo que nas seções 2.2, 3.2 e 4.2.
5.6. Entre
A próxima consulta retornará usuários com idades entre 20 e 50 anos, semelhante às seções anteriores:
QUser qUser = new QUser("user");
Predicate predicate = qUser.age.between(20, 50);
List<User> users = (List<User>) userRepository.findAll(predicate);