1. Oversigt
Når du bruger Spring Data MongoDB, skal vi muligvis begrænse de egenskaber, der er kortlagt fra et databaseobjekt. Typisk kan vi have brug for dette, for eksempel af sikkerhedsmæssige årsager – for at undgå at afsløre følsomme oplysninger gemt på en server. Eller også kan vi for eksempel være nødt til at bortfiltrere en del af de data, der vises i en webapplikation.
I denne korte øvelse vil vi se, hvordan MongoDB anvender feltbegrænsning.
2. MongoDB-feltbegrænsning ved hjælp af projektion
MongoDB bruger Projection til at specificere eller begrænse felter, der skal returneres fra en forespørgsel . Men hvis vi bruger Spring Data, ønsker vi at anvende dette med MongoTemplate eller MongoRepository .
Derfor ønsker vi at oprette testcases for begge MongoTemplate og MongoRepository hvor vi kan anvende feltrestriktioner.
3. Implementering af projektion
3.1. Opsætning af entiteten
Lad os først oprette en Beholdning klasse:
@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. Opsætning af repository
Derefter for at teste MongoRepository , opretter vi et InventoryRepository . Vi bruger også et hvor tilstand med @Query . For eksempel ønsker vi at filtrere efter lagerstatus:
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. Tilføjelse af Maven-afhængighederne
Vi bruger også Embedded MongoDB. Lad os tilføje spring-data-mongodb og de.flapdoodle.embed.mongo afhængigheder til vores pom.xml fil:
<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. Test med MongoRepository og MongoTemplate
Til MongoRepository , vil vi se eksempler, der bruger @Query og anvendelse af feltbegrænsning, mens for MongoTemplate , bruger vi Forespørgsel klasse.
Vi vil forsøge at dække alle forskellige kombinationer af inkludere og ekskludere. Vi vil især se, hvordan man begrænser indlejrede felter eller, mere interessant, arrays ved hjælp af udsnittet ejendom .
For hver test tilføjer vi MongoRepository eksemplet først, efterfulgt af det for MongoTemplate .
4.1. Inkluder kun felter
Lad os starte med at inkludere nogle felter. Alle ekskluderede vil være null . Projektionen tilføjer _id som standard:
List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeItemAndStatusFields("A");
inventoryList.forEach(i -> {
assertNotNull(i.getId());
assertNotNull(i.getItem());
assertNotNull(i.getStatus());
assertNull(i.getSize());
assertNull(i.getInStock());
});
Lad os nu tjekke MongoTemplate version:
Query query = new Query();
query.fields()
.include("item")
.include("status");
4.2. Inkluder og ekskluder felter
Denne gang vil vi se eksempler, der eksplicit inkluderer nogle felter, men udelukker andre – i dette tilfælde vil vi ekskludere _id felt:
List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeItemAndStatusExcludeIdFields("A");
inventoryList.forEach(i -> {
assertNotNull(i.getItem());
assertNotNull(i.getStatus());
assertNull(i.getId());
assertNull(i.getSize());
assertNull(i.getInStock());
});
Den tilsvarende forespørgsel ved hjælp af MongoTemplate ville være:
Query query = new Query();
query.fields()
.include("item")
.include("status")
.exclude("_id");
4.3. Ekskluder kun felter
Lad os fortsætte med at ekskludere nogle felter. Alle andre felter er ikke-null:
List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeAllButStatusAndStockFields("A");
inventoryList.forEach(i -> {
assertNotNull(i.getItem());
assertNotNull(i.getId());
assertNotNull(i.getSize());
assertNull(i.getInStock());
assertNull(i.getStatus());
});
Og lad os se MongoTemplate version:
Query query = new Query();
query.fields()
.exclude("status")
.exclude("inStock");
4.4. Inkluder indlejrede felter
Igen, herunder indlejrede felter vil tilføje dem til vores resultat:
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());
});
Lad os se, hvordan du gør det samme med MongoTemplate :
Query query = new Query();
query.fields()
.include("item")
.include("status")
.include("size.uom");
4.5. Ekskluder indlejrede felter
Ligeledes udelukker du indlejrede felter, så holdes de ude af vores resultat, men det ville tilføje resten af de indlejrede felter :
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());
});
Lad os tage et kig på MongoTemplate version:
Query query = new Query();
query.fields()
.exclude("size.uom");
4.6. Inkluder indlejrede felter i Array
På samme måde som andre felter kan vi også tilføje en projektion af et arrays felt:
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());
});
Lad os implementere det samme ved hjælp af MongoTemplate :
Query query = new Query();
query.fields()
.include("item")
.include("status")
.include("inStock.quantity");
4.7. Inkluder indlejrede felter i Array ved hjælp af slice
MongoDB kan bruge JavaScript-funktioner til at begrænse resultaterne af et array – for eksempel ved kun at få det sidste element i et array ved hjælp af 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());
});
Lad os udføre den samme forespørgsel ved hjælp af MongoTemplate :
Query query = new Query();
query.fields()
.include("item")
.include("status")
.slice("inStock", -1);