1. Обзор
При использовании Spring Data MongoDB нам может потребоваться ограничить свойства, сопоставленные с объектом базы данных. Как правило, нам это может понадобиться, например, из соображений безопасности — чтобы не раскрывать конфиденциальную информацию, хранящуюся на сервере. Или также, например, нам может понадобиться отфильтровать часть данных, отображаемых в веб-приложении.
В этом кратком руководстве мы увидим, как MongoDB применяет ограничения полей.
2. Ограничение полей MongoDB с использованием проекции
MongoDB использует Projection для указания или ограничения полей, возвращаемых из запроса . Однако, если мы используем Spring Data, мы хотим применить это с MongoTemplate
или MongoRepository
.
Поэтому мы хотим создать тестовые случаи как для MongoTemplate,
так и для MongoRepository,
где мы можем применять ограничения полей.
3. Реализация проекции
3.1. Настройка объекта
Во-первых, давайте создадим класс Inventory :
@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. Настройка репозитория
Затем, чтобы протестировать MongoRepository
, мы создаем InventoryRepository
. Мы также будем использовать условие where с
@Query
. Например, мы хотим отфильтровать статус инвентаря:
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. Добавление зависимостей Maven
Мы также будем использовать Embedded MongoDB . Давайте добавим зависимости spring-data-mongodb
`` ` и de.flapdoodle.embed.mongo [
в](https://search.maven.org/artifact/de.flapdoodle.embed/de.flapdoodle.embed.mongo) наш файл
pom.xml` :
<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. Протестируйте с помощью MongoRepository
и MongoTemplate
Для MongoRepository
мы увидим примеры использования @Query
и применения Field Restriction , а для MongoTemplate
мы будем использовать класс Query .
****
Мы постараемся охватить все различные комбинации включения и исключения. В частности, мы увидим, как ограничить встроенные поля или, что более интересно, массивы с помощью свойства slice
.
Для каждого теста мы сначала добавим пример MongoRepository
, а затем пример для MongoTemplate
.
4.1. Включить только поля
Начнем с включения некоторых полей. Все исключенные будут нулевыми
. Проекция добавляет идентификатор
_ по умолчанию:
List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeItemAndStatusFields("A");
inventoryList.forEach(i -> {
assertNotNull(i.getId());
assertNotNull(i.getItem());
assertNotNull(i.getStatus());
assertNull(i.getSize());
assertNull(i.getInStock());
});
Теперь давайте проверим версию MongoTemplate
:
Query query = new Query();
query.fields()
.include("item")
.include("status");
4.2. Включить и исключить поля
На этот раз мы увидим примеры, которые явно включают одни поля, но исключают другие — в этом случае мы исключим поле _ id
:
List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeItemAndStatusExcludeIdFields("A");
inventoryList.forEach(i -> {
assertNotNull(i.getItem());
assertNotNull(i.getStatus());
assertNull(i.getId());
assertNull(i.getSize());
assertNull(i.getInStock());
});
Эквивалентный запрос с использованием MongoTemplate
будет таким:
Query query = new Query();
query.fields()
.include("item")
.include("status")
.exclude("_id");
4.3. Исключать только поля
Продолжим, исключив некоторые поля. Все остальные поля будут ненулевыми:
List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeAllButStatusAndStockFields("A");
inventoryList.forEach(i -> {
assertNotNull(i.getItem());
assertNotNull(i.getId());
assertNotNull(i.getSize());
assertNull(i.getInStock());
assertNull(i.getStatus());
});
И давайте проверим версию MongoTemplate
:
Query query = new Query();
query.fields()
.exclude("status")
.exclude("inStock");
4.4. Включить встроенные поля
Опять же, включение встроенных полей добавит их к нашему результату:
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());
});
Давайте посмотрим, как сделать то же самое с MongoTemplate
:
Query query = new Query();
query.fields()
.include("item")
.include("status")
.include("size.uom");
4.5. Исключить встроенные поля
Аналогичным образом, исключение встроенных полей не позволяет им попасть в наш результат, однако это добавит остальные встроенные поля :
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());
});
Давайте посмотрим на версию MongoTemplate
:
Query query = new Query();
query.fields()
.exclude("size.uom");
4.6. Включить встроенные поля в массив
Аналогично другим полям, мы также можем добавить проекцию поля массива:
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());
});
Давайте реализуем то же самое, используя MongoTemplate
:
Query query = new Query();
query.fields()
.include("item")
.include("status")
.include("inStock.quantity");
4.7. Включить встроенные поля в массив с помощью среза
MongoDB может использовать функции JavaScript для ограничения результатов массива — например, получение только последнего элемента массива с помощью 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());
});
Давайте выполним тот же запрос, используя MongoTemplate
:
Query query = new Query();
query.fields()
.include("item")
.include("status")
.slice("inStock", -1);
5. Вывод
В этой статье мы рассмотрели прогнозы в Spring Data MongoDB.
Мы видели примеры использования полей как
с интерфейсом MongoRepository и аннотацией
@Query
, так и с MongoTemplate
и классом Query
.
``
Как всегда, код этих примеров доступен на GitHub .