MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Um guia para consultas no Spring Data MongoDB

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