Um guia para consultas no Spring Data MongoDB
1. Visão geral
Este artigo se concentrará na construção de diferentestypes of queries in Spring Data MongoDB.
Estaremos olhando documentos de consulta com classesQueryeCriteria, métodos de consulta gerados automaticamente, consultas JSON e QueryDSL.
Para a configuração do Maven, dê uma olhada em nossointroductory article.
2. Consulta de Documentos
Uma das maneiras mais comuns de consultar o MongoDB com Spring Data é usando as classesQueryeCriteria - que refletem muito de perto os operadores nativos.
2.1. Is
Este é simplesmente um critério de igualdade - vamos ver como funciona.
No exemplo a seguir, estamos procurando usuários chamadosEric.
Vejamos nosso banco de dados:
[
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.example.model.User",
"name" : "Eric",
"age" : 45
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581908"),
"_class" : "org.example.model.User",
"name" : "Antony",
"age" : 55
}
}
Agora vamos examinar o código de consulta:
Query query = new Query();
query.addCriteria(Criteria.where("name").is("Eric"));
List users = mongoTemplate.find(query, User.class);
Essa lógica retorna, conforme o esperado:
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.example.model.User",
"name" : "Eric",
"age" : 45
}
2.2. Regex
Um tipo de consulta mais flexível e poderoso é o regex. Este c` ++ `reanima um critério usando um MongoDB$regex que retorna todos os registros adequados para este regexp para este campo.
Funciona de maneira semelhante às operações destartingWith, endingWith - vejamos um exemplo.
Agora estamos procurando por todos os usuários que têm nomes começando comA.
Este é o estado do banco de dados:
[
{
"_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
}
]
Agora vamos criar a consulta:
Query query = new Query();
query.addCriteria(Criteria.where("name").regex("^A"));
List users = mongoTemplate.find(query,User.class);
Isso executa e retorna 2 registros:
[
{
"_id" : ObjectId("55c0e5e5511f0a164a581908"),
"_class" : "org.example.model.User",
"name" : "Antony",
"age" : 33
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581909"),
"_class" : "org.example.model.User",
"name" : "Alice",
"age" : 35
}
]
Aqui está outro exemplo rápido, desta vez procurando por todos os usuários que têm nomes terminados emc:
Query query = new Query();
query.addCriteria(Criteria.where("name").regex("c$"));
List users = mongoTemplate.find(query, User.class);
Então o resultado será:
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.example.model.User",
"name" : "Eric",
"age" : 45
}
2.3. Lt egt
Esses operadores criam um critério usando o operador$lt (menor que) e$gt (maior que).
Vamos dar uma olhada em um exemplo - estamos procurando todos os usuários com idade entre 20 e 50 anos.
O banco de dados é:
[
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.example.model.User",
"name" : "Eric",
"age" : 45
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581908"),
"_class" : "org.example.model.User",
"name" : "Antony",
"age" : 55
}
}
Este código de consulta:
Query query = new Query();
query.addCriteria(Criteria.where("age").lt(50).gt(20));
List users = mongoTemplate.find(query,User.class);
E o resultado - todos os usuários com idade superior a 20 e inferior a 50:
{
"_id" : ObjectId("55c0e5e5511f0a164a581907"),
"_class" : "org.example.model.User",
"name" : "Eric",
"age" : 45
}
2.4. Sort
Sort é 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.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
}
]
Depois de executarsort:
Query query = new Query();
query.with(new Sort(Sort.Direction.ASC, "age"));
List users = mongoTemplate.find(query,User.class);
E aqui está o resultado da consulta - bem classificado porage:
[
{
"_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
Vejamos um exemplo rápido de paginação.
Este é o estado do banco de dados:
[
{
"_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
}
]
Agora, 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.example.model.User",
"name" : "Eric",
"age" : 45
},
{
"_id" : ObjectId("55c0e5e5511f0a164a581908"),
"_class" : "org.example.model.User",
"name" : "Antony",
"age" : 33
}
]
3. Métodos de consulta gerados
Vamos agora explorar o tipo mais comum de consulta que Spring Data geralmente fornece - consultas geradas automaticamente a partir de nomes de métodos.
A única coisa que precisamos fazer para aproveitar esses tipos de consultas é declarar o método na interface do repositório:
public interface UserRepository
extends MongoRepository, QueryDslPredicateExecutor {
...
}
3.1. FindByX
Começaremos de forma simples, explorando o tipo de consulta findBy - neste caso, localizar por nome: __
List findByName(String name);
O mesmo que na seção anterior - 2.1 - a consulta terá os mesmos resultados, localizando todos os usuários com o nome fornecido:
List users = userRepository.findByName("Eric");
3.2. StartingWith e terminando com.
Em 2.2, exploramos uma consulta baseada emregex. Começa e termina com são, obviamente, menos poderosos, mas, no entanto, bastante úteis - especialmente se não tivermos que implementá-los de fato.
Aqui está um exemplo rápido de como as operações seriam: __
List findByNameStartingWith(String regexp);
List findByNameEndingWith(String regexp);
O exemplo de realmente usar isso seria, é claro, muito simples:
List users = userRepository.findByNameStartingWith("A");
List users = userRepository.findByNameEndingWith("c");
E os resultados são exatamente os mesmos.
3.3. Between
Semelhante ao 2.3, isso retornará todos os usuários com idade entreageGTeageLT:
List findByAgeBetween(int ageGT, int ageLT);
A chamada do método resultará na localização exata dos mesmos documentos:
List users = userRepository.findByAgeBetween(20, 50);
3.4. Like eOrderBy
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 com nomes contendo a letraA e também ordenaremos os resultados por idade, em ordem crescente:
List users = userRepository.findByNameLikeOrderByAgeAsc("A");
Para o banco de dados que usamos no 2.4 - o resultado será:
[
{
"_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étodos de consulta JSON
Se não podemos representar uma consulta com a ajuda de um nome de método, ou critérios, podemos fazer algo mais baixo nível -use the @Query annotation.
Com esta anotação, podemos especificar uma consulta bruta - como uma sequência de consulta JSON do Mongo.
4.1. FindBy
Vamos começar de forma simples e ver como representaríamosa find by type of method primeiro:
@Query("{ 'name' : ?0 }")
List findUsersByName(String name);
Este método deve retornar usuários pelo nome - o espaço reservado?0 faz referência ao primeiro parâmetro do método.
List users = userRepository.findUsersByName("Eric");
4.2 $regex
Vejamos tambéma regex driven query - que obviamente produz o mesmo resultado que em 2.2 e 3.2:
@Query("{ 'name' : { $regex: ?0 } }")
List findUsersByRegexpName(String regexp);
O uso também é exatamente o mesmo:
List users = userRepository.findUsersByRegexpName("^A");
List users = userRepository.findUsersByRegexpName("c$");
4.3. $lt e$gt
Vamos agora implementar a consulta lt egt:
@Query("{ 'age' : { $gt: ?0, $lt: ?1 } }")
List findUsersByAgeBetween(int ageGT, int ageLT);
Agora como, agora que o método tem 2 parâmetros, estamos referenciando cada um deles por índice na consulta bruta:?0e?1.
List users = userRepository.findUsersByAgeBetween(20, 50);
5. Consultas QueryDSL
MongoRepository tem um bom suporte para o projetoQueryDSL - portanto, podemos aproveitar essa API agradável e segura para tipos 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:
com.mysema.querydsl
querydsl-mongodb
3.6.6
com.mysema.querydsl
querydsl-apt
3.6.6
5.2. Q-classes
QueryDSL usou Q-classes para criar consultas. Mas, como não queremos realmente criá-los manualmente,we need to generate them de alguma forma.
Vamos usar o plugin apt-maven para fazer isso:
com.mysema.maven
apt-maven-plugin
1.1.3
process
target/generated-sources/java
org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor
Vamos dar uma olhada na classeUser - focando especificamente na anotação@QueryEntity:
@QueryEntity
@Document
public class User {
@Id
private String id;
private String name;
private Integer age;
// standard getters and setters
}
Depois de executar a metaprocess do ciclo de vida do Maven (ou qualquer outra meta após essa) - o plugin aptwill generate the new classes emtarget/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 extends User> path) {
super(path.getType(), path.getMetadata());
}
public QUser(PathMetadata> metadata) {
super(User.class, metadata);
}
}
É com a ajuda desta classe que não criaremos nossas consultas.
Como uma observação lateral - se você estiver usando o Eclipse, a introdução deste plug-in irá gerar o seguinte aviso no pom:
Você precisa executar o build com JDK ou ter tools.jar no classpath. Se isso ocorrer durante a construção do eclipse, certifique-se de executar o eclipse no JDK também (com.mysema.maven: apt-maven-plugin: 1.1.3: process: default: generate-sources
Maveninstall funciona bem e a classeQUser é gerada, mas um plugin é destacado no pom.
Uma solução rápida é apontar manualmente para o JDK emeclipse.ini:
...
-vm
{path_to_jdk}\jdk{your_version}\bin\javaw.exe
5.3. The New Repository
Agora precisamos habilitar o suporte QueryDSL em nossos repositórios - o que é feito simplesmenteextending the QueryDslPredicateExecutor interface:
public interface UserRepository extends
MongoRepository, QuerydslPredicateExecutor
5.4. Eq
Com o suporte ativado,let’s now implement the same queries como os que ilustramos antes.
Começaremos com igualdade simples:
QUser qUser = new QUser("user");
Predicate predicate = qUser.name.eq("Eric");
List users = (List) userRepository.findAll(predicate);
5.5. StartingWith eEndingWith
Da mesma forma, vamos implementar as consultas anteriores - e encontrar usuários com nomes que começam comA:
QUser qUser = new QUser("user");
Predicate predicate = qUser.name.startsWith("A");
List users = (List) userRepository.findAll(predicate);
E terminando comc:
QUser qUser = new QUser("user");
Predicate predicate = qUser.name.endsWith("c");
List users = (List) userRepository.findAll(predicate);
O resultado é o mesmo que em 2.2, 3.2 ou 4.2.
5.6. Between
A próxima consulta retornará usuários com idade entre 20 e 50 - semelhante às seções anteriores:
QUser qUser = new QUser("user");
Predicate predicate = qUser.age.between(20, 50);
List users = (List) userRepository.findAll(predicate);
6. Conclusão
Neste artigo, exploramos as várias maneiras pelas quais podemos consultar usando o Spring Data MongoDB.
É interessante dar um passo para trás e ver quantas maneiras poderosas temos para consultar o MongoDB - variando de controle limitado até o controle total com consultas brutas.
A implementação de todos esses exemplos e fragmentos de códigocan be found inthe GitHub project - este é um projeto baseado em Eclipse, portanto, deve ser fácil de importar e executar como está.