Рубрики
Без рубрики

Весенние данные MongoDB: Прогнозы и агрегации

Краткое и практическое руководство по прогнозам и агрегациям в весенних данных MongoDB

Автор оригинала: baeldung.

1. Обзор

Spring Data MongoDB предоставляет простые абстракции высокого уровня для родного языка запросов MongoDB. В этой статье мы рассмотрим поддержку структуры прогнозов и агрегирования.

Если вы новичок в этой теме, обратитесь к нашей вводной статье Введение в Spring Data MongoDB .

2. Проекция

В MongoDB проекции-это способ извлечения только необходимых полей документа из базы данных. Это уменьшает объем данных, которые должны быть переданы с сервера базы данных на клиент, и, следовательно, повышает производительность.

С помощью Spring Data Mongodb проекции можно использовать как с MongoTemplate , так и с |/MongoRepository.

Прежде чем двигаться дальше, давайте рассмотрим модель данных, которую мы будем использовать:

@Document
public class User {
    @Id
    private String id;
    private String name;
    private Integer age;
    
    // standard getters and setters
}

2.1. Проекции С использованием MongoTemplate

Методы include() и exclude() в классе Field используются для включения и исключения полей соответственно:

Query query = new Query();
query.fields().include("name").exclude("id");
List john = mongoTemplate.find(query, User.class);

Эти методы могут быть объединены в цепочку, чтобы включать или исключать несколько полей. Поле, помеченное как @Id ( _id в базе данных), всегда извлекается, если явно не исключено.

Исключенные поля являются null в экземпляре класса модели, когда записи извлекаются с помощью проекции. В случае, когда поля имеют примитивный тип или их класс-оболочку, значения исключенных полей являются значениями по умолчанию примитивных типов.

Например, String будет null , int |/Integer будет 0 и boolean |/Boolean будет false .

Таким образом, в приведенном выше примере поле name будет John , id будет null и возраст будет 0.

2.2. Проекции С Использованием MongoRepository

При использовании репозиториев Mongo поля аннотации @Query могут быть определены в формате JSON:

@Query(value="{}", fields="{name : 1, _id : 0}")
List findNameAndExcludeId();

Результат будет таким же, как при использовании MongoTemplate. Значение =” {}” означает отсутствие фильтров, и, следовательно, все документы будут извлечены.

3. Агрегация

Агрегация в MongoDB была построена для обработки данных и возврата вычисленных результатов. Данные обрабатываются поэтапно, и выходные данные одного этапа предоставляются в качестве входных данных для следующего этапа. Эта способность применять преобразования и выполнять вычисления с данными поэтапно делает агрегацию очень мощным инструментом для аналитики.

Spring Data MongoDB предоставляет абстракцию для собственных запросов агрегации с использованием трех классов Aggregation , которые обертывают запрос агрегации, AggregationOperation , который обертывает отдельные этапы конвейера, и AggregationResults , который является контейнером результата, полученного агрегацией.

Для выполнения и агрегации сначала создайте конвейеры агрегации с помощью методов статического построителя в классе Aggregation , затем создайте экземпляр Aggregation с помощью метода Newagregation() в классе Aggregation и, наконец, запустите агрегацию с помощью MongoTemplate :

MatchOperation matchStage = Aggregation.match(new Criteria("foo").is("bar"));
ProjectionOperation projectStage = Aggregation.project("foo", "bar.baz");
        
Aggregation aggregation 
  = Aggregation.newAggregation(matchStage, projectStage);

AggregationResults output 
  = mongoTemplate.aggregate(aggregation, "foobar", OutType.class);

Обратите внимание, что как Операция сопоставления , так и Операция проекции реализуют Операцию агрегирования . Существуют аналогичные реализации для других конвейеров агрегации. Тип выхода – это модель данных для ожидаемого вывода.

Теперь мы рассмотрим несколько примеров и их объяснения, чтобы охватить основные конвейеры и операторы агрегации.

Набор данных, который мы будем использовать в этой статье, содержит подробную информацию обо всех почтовых кодах в США, которые можно загрузить из репозитория MongoDB .

Давайте рассмотрим пример документа после импорта его в коллекцию под названием zips в базе данных test .

{
    "_id" : "01001",
    "city" : "AGAWAM",
    "loc" : [
        -72.622739,
        42.070206
    ],
    "pop" : 15338,
    "state" : "MA"
}

Для простоты и краткости кода в следующих фрагментах кода мы будем предполагать, что все статические методы класса Aggregation статически импортируются.

3.1. Получить Все Штаты С Населением Более 10 Миллионов В Порядке Убывания Численности Населения

Здесь у нас будет три трубопровода:

  1. $group этап подведения итогов по населению всех почтовых индексов
  2. $match этап фильтрации штатов с населением более 10 миллионов человек
  3. $sort этап сортировки всех документов в порядке убывания численности населения

Ожидаемый результат будет иметь поле _id как состояние и поле statePop с общей численностью населения штата. Давайте создадим для этого модель данных и запустим агрегацию:

public class StatePoulation {
 
    @Id
    private String state;
    private Integer statePop;
 
    // standard getters and setters
}

Аннотация @Id сопоставит поле _id с выводом в состояние в модели:

GroupOperation groupByStateAndSumPop = group("state")
  .sum("pop").as("statePop");
MatchOperation filterStates = match(new Criteria("statePop").gt(10000000));
SortOperation sortByPopDesc = sort(Sort.by(Direction.DESC, "statePop"));

Aggregation aggregation = newAggregation(
  groupByStateAndSumPop, filterStates, sortByPopDesc);
AggregationResults result = mongoTemplate.aggregate(
  aggregation, "zips", StatePopulation.class);

Класс Aggregation Results реализует Iterable , и, следовательно, мы можем перебирать его и печатать результаты.

Если модель выходных данных неизвестна, можно использовать стандартный класс MongoDB Document .

3.2. Получить наименьшее государство по среднему населению города

Для решения этой задачи нам понадобится четыре этапа:

  1. $group для суммирования общей численности населения каждого города
  2. $group для расчета средней численности населения каждого штата
  3. $sort stage для упорядочения штатов по их среднему городскому населению в порядке возрастания
  4. $limit чтобы получить первый штат с самым низким средним населением города

Хотя это не обязательно, мы будем использовать дополнительный этап $project для переформатирования документа в соответствии с моделью данных StatePopulation .

GroupOperation sumTotalCityPop = group("state", "city")
  .sum("pop").as("cityPop");
GroupOperation averageStatePop = group("_id.state")
  .avg("cityPop").as("avgCityPop");
SortOperation sortByAvgPopAsc = sort(Sort.by(Direction.ASC, "avgCityPop"));
LimitOperation limitToOnlyFirstDoc = limit(1);
ProjectionOperation projectToMatchModel = project()
  .andExpression("_id").as("state")
  .andExpression("avgCityPop").as("statePop");

Aggregation aggregation = newAggregation(
  sumTotalCityPop, averageStatePop, sortByAvgPopAsc,
  limitToOnlyFirstDoc, projectToMatchModel);

AggregationResults result = mongoTemplate
  .aggregate(aggregation, "zips", StatePopulation.class);
StatePopulation smallestState = result.getUniqueMappedResult();

В этом примере мы уже знаем, что в результате будет только один документ, так как на последнем этапе мы ограничиваем количество выходных документов 1. Таким образом, мы можем вызвать get Unique Mapped Result () , чтобы получить требуемый экземпляр State Population .

Еще одна вещь, на которую следует обратить внимание, заключается в том, что вместо того, чтобы полагаться на аннотацию @Id для отображения _id в состояние, мы явно сделали это на этапе проекции.

3.3. Получить штат С Максимальным и Минимальным Почтовыми кодами

Для этого примера нам нужно три этапа:

  1. $group для подсчета количества почтовых индексов для каждого штата
  2. $sort упорядочить штаты по количеству почтовых индексов
  3. $group чтобы найти состояние с максимальными и минимальными почтовыми кодами, используя $first и $last операторы
GroupOperation sumZips = group("state").count().as("zipCount");
SortOperation sortByCount = sort(Direction.ASC, "zipCount");
GroupOperation groupFirstAndLast = group().first("_id").as("minZipState")
  .first("zipCount").as("minZipCount").last("_id").as("maxZipState")
  .last("zipCount").as("maxZipCount");

Aggregation aggregation = newAggregation(sumZips, sortByCount, groupFirstAndLast);

AggregationResults result = mongoTemplate
  .aggregate(aggregation, "zips", Document.class);
Document document= result.getUniqueMappedResult();

Здесь мы не использовали какую-либо модель, но использовали Документ , уже поставляемый с драйвером MongoDB.

4. Заключение

В этой статье мы узнали, как извлечь указанные поля документа в MongoDB, используя проекции в Spring Data MongoDB.

Мы также узнали о поддержке платформы агрегации MongoDB в Spring Data. Мы рассмотрели основные этапы агрегирования – группирование, проект, сортировка, ограничение и сопоставление, а также рассмотрели некоторые примеры его практического применения. Полный исходный код доступен на GitHub .