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