Перейти к основному содержимому

Возврат только определенных полей для запроса в Spring Data MongoDB

· 5 мин. чтения

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 .