sql >> Base de Datos >  >> NoSQL >> MongoDB

Una guía para consultas en Spring Data MongoDB

1. Resumen

Este tutorial se centrará en la creación de diferentes tipos de consultas en Spring Data MongoDB .

Vamos a ver cómo consultar documentos con Query y Criterios clases, métodos de consulta generados automáticamente, consultas JSON y QueryDSL.

Para la configuración de Maven, echa un vistazo a nuestro artículo introductorio.

2. Consulta de documentos

Una de las formas más comunes de consultar MongoDB con Spring Data es haciendo uso de Query y Criterios clases, que reflejan muy de cerca a los operadores nativos.

2.1. es

Esto es simplemente un criterio que usa la igualdad. Veamos cómo funciona.

En el siguiente ejemplo, buscaremos usuarios llamados Eric .

Miremos nuestra base de datos:

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

Ahora veamos el código de consulta:

Query query = new Query();
query.addCriteria(Criteria.where("name").is("Eric"));
List<User> users = mongoTemplate.find(query, User.class);

Como era de esperar, esta lógica devuelve:

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

2.2. Expresión regular

Un tipo de consulta más flexible y potente es la expresión regular. Esto crea un criterio utilizando un MongoDB $regex que devuelve todos los registros adecuados para la expresión regular de este campo.

Funciona de manera similar a empezando por y terminando con operaciones.

En este ejemplo, buscaremos todos los usuarios cuyos nombres comiencen con A .

Este es el estado de la base de datos:

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

Ahora vamos a crear la consulta:

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

Esto se ejecuta y devuelve 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
    }
]

Aquí hay otro ejemplo rápido, esta vez buscando todos los usuarios cuyos nombres terminen con c :

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

Entonces el resultado será:

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

2.3. Teniente y gt

Estos operadores crean un criterio usando $lt (menor que) y $gt (mayor que) operadores.

Tomemos un ejemplo rápido en el que buscamos a todos los usuarios entre 20 y 50 años.

La base de datos es:

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

El código de consulta:

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

Y los resultados para todos los usuarios con una edad mayor a 20 y menor a 50:

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

2.4. Ordenar

Ordenar se utiliza para especificar un orden de clasificación para los resultados.

El siguiente ejemplo muestra todos los usuarios ordenados por edad en orden ascendente.

Primero, aquí están los datos 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
    }
]

Después de ejecutar ordenar :

Query query = new Query();
query.with(Sort.by(Sort.Direction.ASC, "age"));
List<User> users = mongoTemplate.find(query,User.class);

Y aquí está el resultado de la consulta, bien ordenado por edad :

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

Veamos un ejemplo rápido usando la paginación.

Este es el estado de la base de datos:

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

Ahora aquí está la lógica de consulta, simplemente solicitando una página de tamaño 2:

final Pageable pageableRequest = PageRequest.of(0, 2);
Query query = new Query();
query.with(pageableRequest);

Y el resultado, los 2 documentos, como era de esperar:

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

Ahora exploremos el tipo de consulta más común que Spring Data suele proporcionar, consultas generadas automáticamente a partir de nombres de métodos.

Lo único que debemos hacer para aprovechar este tipo de consultas es declarar el método en la interfaz del repositorio:

public interface UserRepository 
  extends MongoRepository<User, String>, QueryDslPredicateExecutor<User> {
    ...
}

3.1. Buscar por X

Comenzaremos de manera simple, explorando el tipo de consulta findBy. En este caso, usaremos buscar por nombre:

List<User> findByName(String name);

Al igual que en la sección anterior, 2.1, la consulta tendrá los mismos resultados, encontrando todos los usuarios con el nombre dado:

List<User> users = userRepository.findByName("Eric");

3.2. Empezando con y terminando con

En la sección 2.2, exploramos una regex consulta basada. Los comienzos y los fines son, por supuesto, menos poderosos, pero sin embargo bastante útiles, especialmente si no tenemos que implementarlos realmente.

Aquí hay un ejemplo rápido de cómo se verían las operaciones:

List<User> findByNameStartingWith(String regexp);
List<User> findByNameEndingWith(String regexp);

El ejemplo de usar esto sería, por supuesto, muy simple:

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

Y los resultados son exactamente los mismos.

3.3. Entre

Similar a la sección 2.3, esto devolverá todos los usuarios con edades entre ageGT y edadLT:

List<User> findByAgeBetween(int ageGT, int ageLT);

Al llamar al método, se encontrarán exactamente los mismos documentos:

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

3.4. Me gusta y Ordenar por

Veamos un ejemplo más avanzado esta vez, combinando dos tipos de modificadores para la consulta generada.

Vamos a buscar a todos los usuarios cuyos nombres contengan la letra A, y también vamos a ordenar los resultados por edad, en orden ascendente:

List<User> users = userRepository.findByNameLikeOrderByAgeAsc("A");

Para la base de datos que usamos en la sección 2.4, el 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

Si no podemos representar una consulta con la ayuda de un nombre de método o criterio, podemos hacer algo más bajo, usar @Query anotación .

Con esta anotación, podemos especificar una consulta sin procesar como una cadena de consulta Mongo JSON.

4.1. Buscar por

Comencemos de manera simple y veamos cómo representaríamos una búsqueda por tipo de método primero:

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

Este método debería devolver los usuarios por nombre. El marcador de posición ?0 hace referencia al primer parámetro del método.

List<User> users = userRepository.findUsersByName("Eric");

4.2. $ expresión regular

También podemos ver una consulta impulsada por expresiones regulares, que por supuesto produce el mismo resultado que en las secciones 2.2 y 3.2:

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

El uso también es exactamente el mismo:

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

4.3. $lt y $gt

Ahora implementemos lt y gt consulta:

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

Ahora que el método tiene 2 parámetros, hacemos referencia a cada uno de ellos por índice en la consulta sin formato, ?0 y ?1:

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

5. Consultas QueryDSL

Repositorio Mongo tiene un buen soporte para el proyecto QueryDSL, por lo que también podemos aprovechar esa API agradable y segura.

5.1. Las dependencias Maven

Primero, asegurémonos de tener las dependencias de Maven correctas definidas en el 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 -clases

QueryDSL usó Q-classes para crear consultas, pero como realmente no queremos crearlas a mano, necesitamos generarlas de alguna manera.

Vamos a usar el complemento apt-maven para hacer eso:

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

Veamos el Usuario clase, centrándose específicamente en @QueryEntity anotación:

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

Después de ejecutar el proceso objetivo del ciclo de vida de Maven (o cualquier otro objetivo después de ese), el complemento apt generará las nuevas clases en target/generated-sources/java/{la estructura de su paquete} :

/**
 * 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);
    }
}

Es debido a esta clase que no necesitamos crear nuestras consultas.

Como nota al margen, si usamos Eclipse, la introducción de este complemento generará la siguiente advertencia en pom:

La instalación de Maven funciona bien y el QUser se genera la clase, pero se resalta un complemento en el pom.

Una solución rápida es apuntar manualmente al JDK en eclipse.ini :

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

5.3. El nuevo repositorio

Ahora necesitamos habilitar la compatibilidad con QueryDSL en nuestros repositorios, lo que se hace simplemente extendiendo el QueryDslPredicateExecutor interfaz :

public interface UserRepository extends 
  MongoRepository<User, String>, QuerydslPredicateExecutor<User>

5.4. Eq

Con el soporte habilitado, ahora implementemos las mismas consultas como los que ilustramos antes.

Empezaremos con la igualdad simple:

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

5.5. Empezando con y terminando con

De manera similar, implementemos las consultas anteriores y busquemos usuarios con nombres que comiencen con A :

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

Además de terminar con c :

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

El resultado es el mismo que en las secciones 2.2, 3.2 y 4.2.

5.6. Entre

La siguiente consulta devolverá usuarios con edades entre 20 y 50 años, similar a las secciones anteriores:

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