1. Panoramica
Quando si utilizza Spring Data MongoDB, potrebbe essere necessario limitare le proprietà mappate da un oggetto database. In genere, potremmo averne bisogno, ad esempio, per motivi di sicurezza, per evitare di esporre informazioni riservate archiviate su un server. Oppure, ad esempio, potremmo dover filtrare parte dei dati visualizzati in un'applicazione web.
In questo breve tutorial, vedremo come MongoDB applica la restrizione dei campi.
2. Limitazione dei campi MongoDB mediante proiezione
MongoDB utilizza Projection per specificare o limitare i campi da restituire da una query . Tuttavia, se utilizziamo Spring Data, vogliamo applicarlo con MongoTemplate o MongoRepository .
Pertanto, vogliamo creare casi di test per entrambi MongoTemplate e MongoRepository dove possiamo applicare restrizioni sul campo.
3. Implementazione della proiezione
3.1. Configurazione dell'entità
Innanzitutto, creiamo un Inventario classe:
@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. Configurazione del repository
Quindi, per testare MongoRepository , creiamo un InventoryRepository . Useremo anche un dove condizione con @Query . Ad esempio, vogliamo filtrare lo stato dell'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. Aggiunta delle dipendenze Maven
Utilizzeremo anche Embedded MongoDB. Aggiungiamo spring-data-mongodb e de.flapdoodle.embed.mongo dipendenze dal nostro pom.xml file:
<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. Prova utilizzando MongoRepository e Modello Mongo
Per MongoRepository , vedremo esempi utilizzando @Query e applicando la restrizione sul campo, mentre per MongoTemplate , utilizzeremo il Interrogazione classe.
Cercheremo di coprire tutte le diverse combinazioni di inclusione ed esclusione. In particolare, vedremo come limitare i campi incorporati o, cosa più interessante, gli array usando la fetta proprietà .
Per ogni test, aggiungeremo il MongoRepository prima l'esempio, seguito da quello per MongoTemplate .
4.1. Includi solo campi
Iniziamo includendo alcuni campi. Tutti gli esclusi saranno nulli . La proiezione aggiunge l'_id per impostazione predefinita:
List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeItemAndStatusFields("A");
inventoryList.forEach(i -> {
assertNotNull(i.getId());
assertNotNull(i.getItem());
assertNotNull(i.getStatus());
assertNull(i.getSize());
assertNull(i.getInStock());
});
Ora, diamo un'occhiata al MongoTemplate versione:
Query query = new Query();
query.fields()
.include("item")
.include("status");
4.2. Includi ed escludi campi
Questa volta, vedremo esempi che includono esplicitamente alcuni campi ma ne escludono altri:in questo caso, escluderemo l'_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 query equivalente che utilizza MongoTemplate sarebbe:
Query query = new Query();
query.fields()
.include("item")
.include("status")
.exclude("_id");
4.3. Escludi solo campi
Continuiamo escludendo alcuni campi. Tutti gli altri campi non saranno nulli:
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, diamo un'occhiata al MongoTemplate versione:
Query query = new Query();
query.fields()
.exclude("status")
.exclude("inStock");
4.4. Includi campi incorporati
Anche in questo caso, l'inclusione dei campi incorporati li aggiungerà al nostro risultato:
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());
});
Vediamo come fare lo stesso con MongoTemplate :
Query query = new Query();
query.fields()
.include("item")
.include("status")
.include("size.uom");
4.5. Escludi campi incorporati
Allo stesso modo, escludere i campi incorporati li tiene fuori dal nostro risultato, tuttavia, aggiungerebbe il resto dei campi incorporati :
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());
});
Diamo un'occhiata al MongoTemplate versione:
Query query = new Query();
query.fields()
.exclude("size.uom");
4.6. Includi campi incorporati nell'array
Analogamente ad altri campi, possiamo anche aggiungere una proiezione del campo di un 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());
});
Implementiamo lo stesso usando MongoTemplate :
Query query = new Query();
query.fields()
.include("item")
.include("status")
.include("inStock.quantity");
4.7. Includi i campi incorporati nell'array usando slice
MongoDB può utilizzare le funzioni JavaScript per limitare i risultati di un array, ad esempio ottenendo solo l'ultimo elemento in un 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());
});
Eseguiamo la stessa query utilizzando MongoTemplate :
Query query = new Query();
query.fields()
.include("item")
.include("status")
.slice("inStock", -1);