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

Retornar apenas campos específicos para uma consulta no Spring Data MongoDB

1. Visão geral


Ao usar o Spring Data MongoDB, talvez seja necessário restringir as propriedades mapeadas de um objeto de banco de dados. Normalmente, podemos precisar disso, por exemplo, por motivos de segurança – para evitar a exposição de informações confidenciais armazenadas em um servidor. Ou também, por exemplo, podemos precisar filtrar parte dos dados exibidos em um aplicativo da web.

Neste breve tutorial, veremos como o MongoDB aplica a restrição de campo.

2. Restrição de campos do MongoDB usando projeção


MongoDB usa Projeção para especificar ou restringir campos para retornar de uma consulta . No entanto, se estivermos usando Spring Data, queremos aplicar isso com MongoTemplate ou MongoRepository .

Portanto, queremos criar casos de teste para MongoTemplate e MongoRepository onde podemos aplicar restrições de campo.

3. Implementando a projeção

3.1. Configurando a Entidade


Primeiro, vamos criar um Inventário aula:
@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 o Repositório


Em seguida, para testar o MongoRepository , criamos um InventoryRepository . Também usaremos um onde condição com @Query . Por exemplo, queremos filtrar pelo status do inventário:
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. Adicionando as dependências do Maven


Também usaremos o MongoDB incorporado. Vamos adicionar o spring-data-mongodb e de.flapdoodle.embed.mongo dependências para nosso pom.xml Arquivo:
<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. Teste usando o MongoRepository e MongoTemplate


Para MongoRepository , veremos exemplos usando @Query e aplicando a Restrição de Campo, enquanto para MongoTemplate , usaremos o  Consulta  classe.

Tentaremos cobrir todas as diferentes combinações de inclusão e exclusão. Em particular, veremos como restringir campos incorporados ou, mais interessante, arrays usando a fatia propriedade .

Para cada teste, adicionaremos o MongoRepository exemplo primeiro, seguido por um para MongoTemplate .

4.1. Incluir apenas campos


Vamos começar incluindo alguns campos. Todos os excluídos serão null . A projeção adiciona o _id por padrão:
List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeItemAndStatusFields("A");

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

Agora, vamos conferir o MongoTemplate versão:
Query query = new Query();
 query.fields()
   .include("item")
   .include("status");

4.2. Incluir e excluir campos


Desta vez, veremos exemplos que incluem explicitamente alguns campos, mas excluem outros. Nesse caso, excluiremos o _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());
});

A consulta equivalente usando MongoTemplate seria:
Query query = new Query();
query.fields()
  .include("item")
  .include("status")
  .exclude("_id");

4.3. Apenas Excluir campos


Vamos continuar excluindo alguns campos. Todos os outros campos serão não 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());
});

E vamos conferir o MongoTemplate versão:
Query query = new Query();
query.fields()
  .exclude("status")
  .exclude("inStock");

4.4. Incluir campos incorporados


Novamente, incluir campos incorporados os adicionará ao nosso 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());
});

Vamos ver como fazer o mesmo com MongoTemplate :
Query query = new Query();
query.fields()
  .include("item")
  .include("status")
  .include("size.uom");

4.5. Excluir campos incorporados


Da mesma forma, excluir campos incorporados os mantém fora do nosso resultado, no entanto, adicionaria o restante dos campos incorporados :
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());
});

Vamos dar uma olhada no MongoTemplate versão:
Query query = new Query();
query.fields()
  .exclude("size.uom");

4.6. Incluir campos incorporados na matriz


Da mesma forma que outros campos, também podemos adicionar uma projeção do campo de um array:
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());
});

Vamos implementar o mesmo usando MongoTemplate :
Query query = new Query();
query.fields()
  .include("item")
  .include("status")
  .include("inStock.quantity");

4.7. Incluir campos incorporados na matriz usando slice


O MongoDB pode usar funções JavaScript para limitar os resultados de um array – por exemplo, obtendo apenas o último elemento de um array 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());
});

Vamos realizar a mesma consulta usando MongoTemplate :
Query query = new Query();
query.fields()
  .include("item")
  .include("status")
  .slice("inStock", -1);