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

Devolver solo campos específicos para una consulta en Spring Data MongoDB

1. Resumen

Al usar Spring Data MongoDB, es posible que debamos restringir las propiedades asignadas desde un objeto de base de datos. Por lo general, podemos necesitar esto, por ejemplo, por razones de seguridad, para evitar exponer información confidencial almacenada en un servidor. O también, por ejemplo, puede que necesitemos filtrar parte de los datos que se muestran en una aplicación web.

En este breve tutorial, veremos cómo MongoDB aplica la restricción de campos.

2. Restricción de campos de MongoDB mediante proyección

MongoDB usa Projection para especificar o restringir los campos que se devuelven de una consulta . Sin embargo, si usamos Spring Data, queremos aplicar esto con MongoTemplate o Repositorio Mongo .

Por lo tanto, queremos crear casos de prueba para ambos MongoTemplate y Repositorio Mongo donde podemos aplicar restricciones de campo.

3. Implementando Proyección

3.1. Configuración de la Entidad

Primero, creemos un Inventario clase:

@Document(collection = "inventory")
public class Inventory {

    @Id
    private String id;
    private String status;
    private Size size;
    private InStock inStock;

    // standard getters and setters    
}

3.2. Configurando el Repositorio

Luego, para probar MongoRepository , creamos un InventoryRepository . También usaremos un donde condición con @Query . Por ejemplo, queremos filtrar por el estado del inventario:

public interface InventoryRepository extends MongoRepository<Inventory, String> {

    @Query(value = "{ 'status' : ?0 }", fields = "{ 'item' : 1, 'status' : 1 }")
    List<Inventory> findByStatusIncludeItemAndStatusFields(String status);

    @Query(value = "{ 'status' : ?0 }", fields = "{ 'item' : 1, 'status' : 1, '_id' : 0 }")
    List<Inventory> findByStatusIncludeItemAndStatusExcludeIdFields(String status);

    @Query(value = "{ 'status' : ?0 }", fields = "{ 'status' : 0, 'inStock' : 0 }")
    List<Inventory> findByStatusIncludeAllButStatusAndStockFields(String status);

    @Query(value = "{ 'status' : ?0 }", fields = "{ 'item' : 1, 'status' : 1, 'size.uom': 1 }")
    List<Inventory> findByStatusIncludeEmbeddedFields(String status);

    @Query(value = "{ 'status' : ?0 }", fields = "{ 'size.uom': 0 }")
    List<Inventory> findByStatusExcludeEmbeddedFields(String status);

    @Query(value = "{ 'status' : ?0 }", fields = "{ 'item' : 1, 'status' : 1, 'inStock.quantity': 1 }")
    List<Inventory> findByStatusIncludeEmbeddedFieldsInArray(String status);

    @Query(value = "{ 'status' : ?0 }", fields = "{ 'item' : 1, 'status' : 1, 'inStock': { $slice: -1 } }")
    List<Inventory> findByStatusIncludeEmbeddedFieldsLastElementInArray(String status);

}

3.3. Agregar las dependencias de Maven

También usaremos Embedded MongoDB. Agreguemos el spring-data-mongodb y de.flapdoodle.embed.mongo dependencias a nuestro pom.xml archivo:

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-mongodb</artifactId>
    <version>3.0.3.RELEASE</version>
</dependency>
<dependency>
    <groupId>de.flapdoodle.embed</groupId>
    <artifactId>de.flapdoodle.embed.mongo</artifactId>
    <version>3.2.6</version>
    <scope>test</scope>
</dependency>

4. Prueba usando MongoRepository y MongoTemplate

Para MongoRepository , veremos ejemplos usando @Query y aplicar Restricción de campo, mientras que para MongoTemplate , usaremos  Consulta  clase.

Intentaremos cubrir todas las diferentes combinaciones de incluir y excluir. En particular, veremos cómo restringir los campos incrustados o, más interesante, las matrices usando el segmento propiedad .

Para cada prueba, agregaremos el MongoRepository primero el ejemplo, seguido del de MongoTemplate .

4.1. Incluir solo campos

Comencemos por incluir algunos campos. Todos los excluidos serán null . La proyección agrega el _id por defecto:

List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeItemAndStatusFields("A");

inventoryList.forEach(i -> {
  assertNotNull(i.getId());
  assertNotNull(i.getItem());
  assertNotNull(i.getStatus());
  assertNull(i.getSize());
  assertNull(i.getInStock());
});

Ahora, echemos un vistazo a la MongoTemplate versión:

Query query = new Query();
 query.fields()
   .include("item")
   .include("status");

4.2. Incluir y excluir campos

Esta vez, veremos ejemplos que incluyen explícitamente algunos campos pero excluyen otros; en este caso, excluiremos el _id campo:

List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeItemAndStatusExcludeIdFields("A");

inventoryList.forEach(i -> {
   assertNotNull(i.getItem());
   assertNotNull(i.getStatus());
   assertNull(i.getId());
   assertNull(i.getSize());
   assertNull(i.getInStock());
});

La consulta equivalente usando MongoTemplate sería:

Query query = new Query();
query.fields()
  .include("item")
  .include("status")
  .exclude("_id");

4.3. Excluir solo campos

Sigamos excluyendo algunos campos. Todos los demás campos no serán nulos:

List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeAllButStatusAndStockFields("A");

inventoryList.forEach(i -> {
  assertNotNull(i.getItem());
  assertNotNull(i.getId());
  assertNotNull(i.getSize());
  assertNull(i.getInStock());
  assertNull(i.getStatus());
});

Y, echemos un vistazo a la MongoTemplate versión:

Query query = new Query();
query.fields()
  .exclude("status")
  .exclude("inStock");

4.4. Incluir campos incrustados

Nuevamente, incluir campos incrustados los agregará a nuestro resultado:

List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeEmbeddedFields("A");

inventoryList.forEach(i -> {
  assertNotNull(i.getItem());
  assertNotNull(i.getStatus());
  assertNotNull(i.getId());
  assertNotNull(i.getSize());
  assertNotNull(i.getSize().getUom());
  assertNull(i.getSize().getHeight());
  assertNull(i.getSize().getWidth());
  assertNull(i.getInStock());
});

Veamos cómo hacer lo mismo con MongoTemplate :

Query query = new Query();
query.fields()
  .include("item")
  .include("status")
  .include("size.uom");

4.5. Excluir campos incrustados

Del mismo modo, excluir campos incrustados los mantiene fuera de nuestro resultado, sin embargo, agregaría el resto de los campos incrustados :

List<Inventory> inventoryList = inventoryRepository.findByStatusExcludeEmbeddedFields("A");

inventoryList.forEach(i -> {
  assertNotNull(i.getItem());
  assertNotNull(i.getStatus());
  assertNotNull(i.getId());
  assertNotNull(i.getSize());
  assertNull(i.getSize().getUom());
  assertNotNull(i.getSize().getHeight());
  assertNotNull(i.getSize().getWidth());
  assertNotNull(i.getInStock());
});

Echemos un vistazo a la MongoTemplate versión:

Query query = new Query();
query.fields()
  .exclude("size.uom");

4.6. Incluir campos incrustados en matriz

De manera similar a otros campos, también podemos agregar una proyección del campo de una matriz:

List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeEmbeddedFieldsInArray("A");

inventoryList.forEach(i -> {
  assertNotNull(i.getItem());
  assertNotNull(i.getStatus());
  assertNotNull(i.getId());
  assertNotNull(i.getInStock());
  i.getInStock()
    .forEach(stock -> {
      assertNull(stock.getWareHouse());
      assertNotNull(stock.getQuantity());
     });
  assertNull(i.getSize());
});

Implementemos lo mismo usando MongoTemplate :

Query query = new Query();
query.fields()
  .include("item")
  .include("status")
  .include("inStock.quantity");

4.7. Incluir campos incrustados en matriz usando segmento

MongoDB puede usar funciones de JavaScript para limitar los resultados de una matriz; por ejemplo, obtener solo el último elemento de una matriz usando slice :

List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeEmbeddedFieldsLastElementInArray("A");

inventoryList.forEach(i -> {
  assertNotNull(i.getItem());
  assertNotNull(i.getStatus());
  assertNotNull(i.getId());
  assertNotNull(i.getInStock());
  assertEquals(1, i.getInStock().size());
  assertNull(i.getSize());
});

Realicemos la misma consulta usando MongoTemplate :

Query query = new Query();
query.fields()
  .include("item")
  .include("status")
  .slice("inStock", -1);