1. Przegląd
W przypadku korzystania z Spring Data MongoDB może być konieczne ograniczenie właściwości mapowanych z obiektu bazy danych. Zazwyczaj możemy tego potrzebować, na przykład ze względów bezpieczeństwa – aby uniknąć ujawnienia poufnych informacji przechowywanych na serwerze. Lub też, na przykład, możemy potrzebować odfiltrować część danych wyświetlanych w aplikacji internetowej.
W tym krótkim samouczku zobaczymy, jak MongoDB stosuje ograniczenia pól.
2. Ograniczenie pól MongoDB przy użyciu projekcji
MongoDB używa projekcji do określania lub ograniczania pól, które mają być zwracane z zapytania . Jeśli jednak używamy Spring Data, chcemy zastosować to za pomocą MongoTemplate lub MongoRepository .
Dlatego chcemy stworzyć przypadki testowe dla obu MongoTemplate i MongoRepository gdzie możemy zastosować ograniczenia terenowe.
3. Wdrażanie projekcji
3.1. Konfiguracja podmiotu
Najpierw utwórzmy Inwentarz klasa:
@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. Konfigurowanie repozytorium
Następnie przetestuj MongoRepository , tworzymy InventoryRepository . Użyjemy również gdzie warunek z @Query . Na przykład chcemy filtrować według stanu zapasów:
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. Dodawanie zależności Mavena
Będziemy również używać osadzonej bazy danych MongoDB. Dodajmy spring-data-mongodb i de.flapdoodle.embed.mongo zależności od naszego pom.xml plik:
<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. Przetestuj za pomocą MongoRepository i MongoTemplate
Dla MongoRepository , zobaczymy przykłady z użyciem @Query i stosowanie ograniczeń dotyczących pól, podczas gdy dla MongoTemplate , użyjemy Zapytanie klasa.
Postaramy się uwzględnić wszystkie różne kombinacje włączania i wykluczania. W szczególności zobaczymy, jak ograniczyć osadzone pola lub, co ciekawsze, tablice za pomocą wycinka właściwość .
Do każdego testu dodamy MongoRepository najpierw przykład, a następnie ten dla MongoTemplate .
4.1. Uwzględnij tylko pola
Zacznijmy od uwzględnienia niektórych pól. Wszystkie wykluczone będą null . Projekcja dodaje _id domyślnie:
List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeItemAndStatusFields("A");
inventoryList.forEach(i -> {
assertNotNull(i.getId());
assertNotNull(i.getItem());
assertNotNull(i.getStatus());
assertNull(i.getSize());
assertNull(i.getInStock());
});
Zobaczmy teraz MongoTemplate wersja:
Query query = new Query();
query.fields()
.include("item")
.include("status");
4.2. Uwzględnij i wyklucz pola
Tym razem zobaczymy przykłady, które wyraźnie zawierają niektóre pola, ale wykluczają inne – w tym przypadku wykluczymy _id pole:
List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeItemAndStatusExcludeIdFields("A");
inventoryList.forEach(i -> {
assertNotNull(i.getItem());
assertNotNull(i.getStatus());
assertNull(i.getId());
assertNull(i.getSize());
assertNull(i.getInStock());
});
Równoważne zapytanie przy użyciu MongoTemplate byłoby:
Query query = new Query();
query.fields()
.include("item")
.include("status")
.exclude("_id");
4.3. Wyłącz tylko pola
Kontynuujmy, wyłączając niektóre pola. Wszystkie inne pola nie będą puste:
List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeAllButStatusAndStockFields("A");
inventoryList.forEach(i -> {
assertNotNull(i.getItem());
assertNotNull(i.getId());
assertNotNull(i.getSize());
assertNull(i.getInStock());
assertNull(i.getStatus());
});
Zobaczmy też MongoTemplate wersja:
Query query = new Query();
query.fields()
.exclude("status")
.exclude("inStock");
4.4. Uwzględnij pola osadzone
Ponownie, uwzględnienie osadzonych pól spowoduje dodanie ich do naszego wyniku:
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());
});
Zobaczmy, jak zrobić to samo z MongoTemplate :
Query query = new Query();
query.fields()
.include("item")
.include("status")
.include("size.uom");
4.5. Wyklucz pola osadzone
Podobnie wykluczenie pól osadzonych sprawia, że nie znajdują się one w naszym wyniku, jednak dodaje resztę pól osadzonych :
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());
});
Przyjrzyjmy się MongoTemplate wersja:
Query query = new Query();
query.fields()
.exclude("size.uom");
4.6. Uwzględnij pola osadzone w tablicy
Podobnie jak w przypadku innych pól, możemy również dodać rzut pola tablicy:
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());
});
Zaimplementujmy to samo za pomocą MongoTemplate :
Query query = new Query();
query.fields()
.include("item")
.include("status")
.include("inStock.quantity");
4.7. Dołącz osadzone pola do tablicy za pomocą slice
MongoDB może używać funkcji JavaScript do ograniczania wyników tablicy – na przykład pobieranie tylko ostatniego elementu tablicy za pomocą 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());
});
Wykonajmy to samo zapytanie za pomocą MongoTemplate :
Query query = new Query();
query.fields()
.include("item")
.include("status")
.slice("inStock", -1);