Моя заметка о Spring Aggregation Query с использованием демонстрационного приложения

Некоторое время я разрабатывал RESTful API в различных технологиях, но недавно перешел на Spring Boot. Поскольку в последнее время Spring появляется и развивается быстрыми темпами, существует отличная поддержка в виде блогов/отчетов. Я делаю небольшую попытку продемонстрировать веб-приложение, которое я создал с помощью Spring Boot.

Какие технологии я использовал?

  • Весенний ботинок
  • Монго БД
  • Мавен
  • HTML, JS, Bootstrap и AJAX

Что особенного в этом приложении?

  • Это приложение использует два RESTful API. Один выполняет простой запрос на получение к серверной БД, т.е. Mongo, а другой API выполняет запрос агрегации к Mongo. Итак, я пытаюсь представить концепцию построения агрегированного запроса в SpringBoot.
  • Я построил все приложение по архитектурному шаблону MVC .
  • Я заполнил свою БД Mongo общедоступными бизнес-данными Yelp. Поэтому, когда вы запрашиваете/используете это приложение, вы почувствуете суть работы с реальными данными. Кроме того, это позволяет любому новичку понять мотивацию разработки запроса агрегации на стороне API, а также размер данных (данные Yelp) помогает понять задержку, связанную с запросом агрегации.
  • Приложение также включает статическую стратегию разбиения на страницы.
  • Приложение использует AJAX для выполнения запросов, поэтому обновление одного компонента (на основе HTTP-запросов) не повлияет на другой компонент.

Как я создавал приложение?

Я заполнил базу данных Mongo бизнес-данными Yelp, используя следующую команду.

mongoimport --db <DB_Name> --collection <Collection_Name> --file yelp_academic_dataset_business.json

Затем мой следующий шаг — создать два простых API.

API 1: getYelpBusiness

Параметры: sort (сортировка отображаемых данных на основе значения параметра) (возможные значения: «name», «stars», «reviewCount»), skip (параметр, используемый для определения смещения и полезный при нумерации страниц, возможные значения: любое целое число)

Функция: этот простой API извлекает 30 (предельное значение по умолчанию) записей из коллекции, где каждая запись показывает название компании, город, звезды (которые показывают рейтинг), ReviewCount (что подразумевает общее количество людей, от которых была получена оценка). )

Пример ответа:

API 2: getYelpBusinessAnalysis

Параметры: skip (параметр, используемый для определения смещения и полезный при разбивке на страницы, возможные значения: любое целое число)

Функция: этот API выполняет агрегированный запрос и извлекает 10 записей, где каждая запись показывает город и соответствующее общее количество бизнес-организаций.

Пример ответа:

На этих снимках экрана Postman указана задержка (время в правом углу), и вы можете заметить, что мой совокупный запрос занимает почти в 3 раза больше времени, чем мой общий запрос. Поэтому при построении агрегированного запроса вы должны помнить о «задержке».

Часть запроса API

Я следовал шаблону MVC при создании API. Соответствующую модель, представление (интерфейс, написанный на HTML и JS), контроллер можно легко понять, пройдясь по моему репозиторию GitHub. Но в этом разделе я продемонстрирую часть API, связанную с запросами.

В следующем коде показана часть запроса API:

package com.example.mongoAggreagtion.query;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.group;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.project;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.sort;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.limit;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.skip;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Repository;
import com.example.mongoAggreagtion.models.DisplayAggregationModel;
import com.example.mongoAggreagtion.models.DisplayModel;
@Repository
public class DisplayQuery {
 
 @Autowired
 MongoTemplate mongoTemplate;
 public List<DisplayModel> getResults(Integer limit, Integer skip, String city, String sort) {
  Query query = new Query();
  query.limit(limit);
  if (skip != null)
   query.skip(skip);
  if (city != null)
   query.addCriteria(Criteria.where("city").is(city));
  if (sort!=null && !sort.equals("name")) {
   if (sort == "reviewCount")
    sort = "review_count";
   query.with(new Sort(Sort.Direction.DESC, sort));
  }
  else
   query.with(new Sort(Sort.Direction.ASC, "name"));
  //fires a simple query on to Mongo Collection
  List<DisplayModel> result = mongoTemplate.find(query, DisplayModel.class, "docs");
  
  return result;
 }
 public List<DisplayAggregationModel> getAnalysisResults(Integer limit, Long skip) {
  Aggregation aggregate;
  if (skip!=null){
  aggregate = newAggregation(
    group("city").count().as("noOfBusinesses"),
    project("noOfBusinesses").and("city").previousOperation(),
    sort(Sort.Direction.DESC, "noOfBusinesses"),
    skip(skip),
    limit(limit)
    );
  }
  else {
   aggregate = newAggregation(
     group("city").count().as("noOfBusinesses"),
     project("noOfBusinesses").and("city").previousOperation(),
     sort(Sort.Direction.DESC, "noOfBusinesses"),
     limit(limit)
     );
  }
  //fires an aggregate query on to Mongo to fetch the count of businesses 
  AggregationResults<DisplayAggregationModel> groupResults = mongoTemplate.aggregate(aggregate, "docs", DisplayAggregationModel.class);
  List<DisplayAggregationModel> result = groupResults.getMappedResults();
  return result;
 }
}

В частности, о части совокупного запроса,

Агрегация Mongo, необходимая для подсчета городов и соответствующих организаций, выглядит следующим образом:

db.docs.aggregate([{$group:{_id:"$city", count:{$sum:1}}}, {"$sort":{'count':-1}}, {"$limit":10}],{allowDiskUse:true})

Перевод этого в Spring выполняется с помощью модуля MongoTemplate, предоставленного Spring, и этот переведенный код:

aggregate = newAggregation(
group("city").count().as("noOfBusinesses"),
project("noOfBusinesses").and("city").previousOperation(),
sort(Sort.Direction.DESC, "noOfBusinesses"),
skip(skip),
limit(limit)
);

Это может помочь вам получить некоторое представление об агрегации Spring-Mongo.

Внешний интерфейс:

Я прикрепил простой View к своим API, используя HTML и JS.

В следующем приложении показано табличное представление ответа API getYelpBusiness. Здесь вы также можете найти статическую разбивку на страницы для этой таблицы, которая динамически обновляет представление таблицы при изменении номера страницы. Кроме того, имеется фильтр (сортировка значений) для уточнения содержимого отображаемой таблицы.

В следующем приложении показано табличное представление ответа API aggregate getYelpBusinessAnalysis. Здесь вы также можете найти статическую разбивку на страницы для этой таблицы, которая динамически обновляет представление таблицы при изменении номера страницы.

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

Еще одна вещь заключается в том, что интерфейс отзывчивый (использование Bootstrap оправдывает это). Следующие приложения подчеркивают эту особенность.

Наконец:

  • Вы можете найти ссылку GitHub для проекта по адресу https://github.com/ravitejathoram/Mongo-SpringBoot-Aggregation. Инструкции по установке можно найти в разделе readme репозитория GitHub.
  • Я пытаюсь сделать заметку о развертывании этого приложения в своей следующей статье, а также добавить форум, чтобы я мог рассказать о методе POST для API.
  • Пожалуйста, прокомментируйте ваши предложения.