Skip to content

Commit

Permalink
5.15. Добавит агрегацию в метод find сервиса `DefaultCategoryServic…
Browse files Browse the repository at this point in the history
…e`. WIP

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

Давайте подумаем, что требуется для подсчёта количества объявлений,
которые соответствуют определённой категории. В первую очередь
необходима информация о самих объявлениях. Информация об объявлениях находится в отдельной коллекции `Offers`. Соответствие между категориями и объявлением происходит через поле `categories`
(массив с идентификаторами категориями).

Чтобы посчитать количество объявлений, которые соответствуют категории, необходимо получить информацию по объявлениям. Чтобы включить документы из другой коллекции MongoDB предлагает оператор `$lookup`. С её помощью можно делать соединения: взять данные из одной коллекции и добавить их в результирующую выборку.

Для работы `$lookup` требуется передать несколько аргументов (объект с параметрами). Сначала определим коллекцию откуда будем брать данные.

Для этого определим ключ `from`. Нам потребуется информацию из
коллекции `offers`. Как будем фильтровать объявления? По идентификатору категории. Поэтому объявим переменную (`let`) и сохраним идентификатор категории в `categoryId`. Позже эту и переменную сможем использовать в построении условия.

Далее опишем конвейер (`pipeline`). В нём можно определить операции,
которые необходимо выполнить над данными. Начнём с фильтрации. Для
этого MongoDB предлагает оператор `$match`. В самых простых случаях ему можно передать значение по которому выполнять фильтрацию. Точно так как мы делали в `find`. Если требуется более сложное условие, можем воспользоваться дополнительными операторами и указать условие в
выражении (`$expr`). В нём мы используем оператор `$in` и создаём
условие: `$$categoryId` должна входить в массив `$categories`.

Переменная `$$categoryId` — это переменная, которую мы определили в
секции `let`.

После фильтрации мы можем немного изменить форму данных. Нам не нужны
абсолютно все поля из `OfferEntity`. Поэтому мы воспользуемся функцией
`$project`. Из полей оставим только `_id`.

Всё. Если сейчас выполнить получение списка категорий и вывести
результат в терминал, вы увидите новое поле `offers`. В нём будут
идентификаторы объектов объявлений. Всё лишнее мы обрезали.

WIP: Задача не решена полностью
  • Loading branch information
AntonovIgor committed Sep 10, 2024
1 parent 2f332e4 commit 602ea1d
Showing 1 changed file with 14 additions and 1 deletion.
15 changes: 14 additions & 1 deletion src/shared/modules/category/category.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,19 @@ export class DefaultCategoryService implements CategoryService {
}

public async find(): Promise<DocumentType<CategoryEntity>[]> {
return this.categoryModel.find();
return this.categoryModel
.aggregate([
{
$lookup: {
from: 'offers',
let: { categoryId: '$_id'},
pipeline: [
{ $match: { $expr: { $in: ['$$categoryId', '$categories'] } } },
{ $project: { _id: 1}}
],
as: 'offers'
},
},
]).exec();
}
}

0 comments on commit 602ea1d

Please sign in to comment.