MongoDB aggregate: как написать первый aggregation-запрос

aggregate в MongoDB нужен, когда обычного find() уже мало. Через aggregation pipeline можно фильтровать документы, группировать их, считать суммы, собирать статистику, менять форму результата и строить отчеты. Pipeline — это цепочка этапов: документ проходит через первый этап, затем через второй, третий и так дальше

Самая частая схема такая:

db.orders.aggregate([
  { $match: { status: "paid" } },
  { $group: { _id: "$userId", total: { $sum: "$amount" } } },
  { $sort: { total: -1 } }
])

Этот запрос берет оплаченные заказы, группирует их по пользователю, считает сумму заказов и сортирует пользователей по общей сумме

Пример данных

Добавим несколько заказов:

db.orders.insertMany([
  { userId: 1, amount: 1200, status: "paid", city: "Sochi" },
  { userId: 1, amount: 800, status: "paid", city: "Sochi" },
  { userId: 2, amount: 1500, status: "new", city: "Moscow" },
  { userId: 2, amount: 2000, status: "paid", city: "Moscow" }
])

Теперь построим отчет по городам:

db.orders.aggregate([
  { $match: { status: "paid" } },
  {
    $group: {
      _id: "$city",
      ordersCount: { $sum: 1 },
      totalAmount: { $sum: "$amount" }
    }
  },
  { $sort: { totalAmount: -1 } }
])

Результат покажет города, количество оплаченных заказов и общую сумму

Что делают основные этапы

$match фильтрует документы. Его часто ставят в начале, чтобы дальше pipeline обрабатывал меньше данных

{ $match: { status: "paid" } }

$group группирует документы и считает агрегаты:

{
  $group: {
    _id: "$city",
    totalAmount: { $sum: "$amount" }
  }
}

$project управляет тем, какие поля попадут в результат:

{
  $project: {
    _id: 0,
    city: "$_id",
    totalAmount: 1
  }
}

$sort сортирует:

{ $sort: { totalAmount: -1 } }

Полный красивый пример

db.orders.aggregate([
  { $match: { status: "paid" } },
  {
    $group: {
      _id: "$city",
      ordersCount: { $sum: 1 },
      totalAmount: { $sum: "$amount" }
    }
  },
  {
    $project: {
      _id: 0,
      city: "$_id",
      ordersCount: 1,
      totalAmount: 1
    }
  },
  { $sort: { totalAmount: -1 } }
])

Такой pipeline уже похож на реальный отчет для админки

Как использовать all в агрегации MongoDB

Если вам нужно выбрать документы, где массив содержит все нужные значения, в фильтре можно использовать $all:

db.products.aggregate([
  { $match: { tags: { $all: ["database", "backend"] } } }
])

Это вернет товары, у которых в tags есть оба значения

Частые ошибки

Поле в group написано без $

Нужно писать "$amount", а не "amount". Без $ MongoDB воспринимает значение как обычную строку

Слишком поздно поставили match

Если фильтр можно применить в начале, ставьте $match первым. Так pipeline обработает меньше документов

Потеряли поле после group

После $group остаются только _id и рассчитанные поля. Если нужное поле не добавили в group, дальше его уже не будет

Смешали find и aggregate

find() подходит для обычной выборки. aggregate() нужен для цепочки обработки и отчетов

Что почитать дальше по MongoDB

Если нужен общий маршрут по теме, откройте рубрику MongoDB. Для соседних задач пригодятся эти разборы:

Как проверить результат на практике

Для MongoDB-материала полезно делать три проверки: сначала выполнить команду на маленьком наборе тестовых документов, затем посмотреть результат через find() или MongoDB Compass, а после этого повторить действие на копии реальной структуры данных. Если запрос меняет документы, сначала запускайте его с фильтром на один документ и только потом расширяйте условие

Еще одна хорошая привычка — записывать исходное состояние и ожидаемый результат. Например: было три документа, после обновления изменился только один; был массив из пяти элементов, после операции остался нужный элемент; индекс появился в getIndexes(). Такая проверка быстро показывает, что вы исправили именно задачу, а не просто получили команду без ошибки

Оцените статью
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x