Группировка данных MongoDB

MongoDBBeginner
Практиковаться сейчас

Введение

В этой лабораторной работе вы изучите основы агрегации данных в MongoDB. Вы сосредоточитесь на использовании конвейера агрегации (aggregation pipeline) для группировки документов, выполнения вычислений над сгруппированными данными, а затем фильтрации, сортировки и преобразования результатов. Эти операции необходимы для анализа данных и создания отчетов в MongoDB. К концу этой лабораторной работы вы будете уверенно использовать оператор $group вместе с другими ключевыми этапами агрегации для извлечения значимых сведений из ваших данных.

Группировка документов по полю

Первым шагом в агрегации данных часто является группировка документов на основе общего поля. На этом шаге вы подключитесь к оболочке MongoDB (MongoDB shell), создадите новую базу данных и коллекцию, а затем используете оператор $group для группировки документов по категориям.

Сначала откройте оболочку MongoDB, выполнив следующую команду в вашем терминале:

mongosh

Оказавшись внутри оболочки, вы увидите приглашение test>. Давайте переключимся на новую базу данных под названием salesdb и вставим некоторые примеры данных о продуктах. MongoDB автоматически создаст базу данных и коллекцию при первой вставке в них данных.

Скопируйте и вставьте следующие команды в оболочку mongosh:

use salesdb
db.products.insertMany([
  { category: "Electronics", brand: "Apple", price: 1200 },
  { category: "Electronics", brand: "Samsung", price: 800 },
  { category: "Electronics", brand: "Sony", price: 950 },
  { category: "Apparel", brand: "Nike", price: 150 },
  { category: "Apparel", brand: "Adidas", price: 120 },
  { category: "Books", brand: "Penguin", price: 25 },
  { category: "Books", brand: "Penguin", price: 35 }
]);

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

db.products.aggregate([
  {
    $group: {
      _id: "$category",
      totalPrice: { $sum: "$price" }
    }
  }
]);

Пример вывода:

[
  { "_id": "Books", "totalPrice": 60 },
  { "_id": "Apparel", "totalPrice": 270 },
  { "_id": "Electronics", "totalPrice": 2950 }
]

Давайте разберем этап агрегации:

  • db.products.aggregate([...]): Это метод, используемый для выполнения агрегации. Он принимает массив этапов, формирующих конвейер (pipeline).
  • $group: Это оператор этапа, который группирует входные документы.
  • _id: "$category": Это выражение определяет ключ для группировки. Здесь мы группируем по значению поля category. Префикс $ указывает на путь к полю.
  • totalPrice: { $sum: "$price" }: Это аккумулятор (accumulator). Он определяет новое поле в выходном документе под названием totalPrice. Оператор $sum вычисляет сумму поля price для всех документов в группе.

Использование нескольких аккумуляторов

Этап $group может одновременно вычислять несколько агрегатов. Вы можете рассчитывать средние значения, находить минимальные или максимальные значения и подсчитывать элементы в каждой группе. Этот шаг демонстрирует, как использовать несколько аккумуляторов в одном этапе $group.

Вы все еще должны находиться в оболочке mongosh, используя базу данных salesdb.

Давайте напишем более сложную агрегацию, которая вычисляет общую цену, среднюю цену и количество продуктов для каждой категории.

db.products.aggregate([
  {
    $group: {
      _id: "$category",
      totalPrice: { $sum: "$price" },
      averagePrice: { $avg: "$price" },
      productCount: { $sum: 1 }
    }
  }
]);

Пример вывода:

[
  {
    "_id": "Books",
    "totalPrice": 60,
    "averagePrice": 30,
    "productCount": 2
  },
  {
    "_id": "Apparel",
    "totalPrice": 270,
    "averagePrice": 135,
    "productCount": 2
  },
  {
    "_id": "Electronics",
    "totalPrice": 2950,
    "averagePrice": 983.3333333333334,
    "productCount": 3
  }
]

Вот новые аккумуляторы, которые мы использовали:

  • averagePrice: { $avg: "$price" }: Оператор $avg вычисляет среднее значение поля price для всех документов в группе.
  • productCount: { $sum: 1 }: Это распространенный способ подсчета документов в группе. Для каждого документа он добавляет 1 к сумме, фактически подсчитывая документы.

Фильтрация сгруппированных данных

После группировки данных часто требуется отфильтровать группы на основе вычисленных значений. Например, вы можете захотеть увидеть только те категории, где общий объем продаж превышает определенную сумму. Для этой цели используется этап $match. Его можно разместить после этапа $group для фильтрации сгруппированных документов.

Найдем категории, где общая цена продуктов больше 500.

db.products.aggregate([
  {
    $group: {
      _id: "$category",
      totalPrice: { $sum: "$price" }
    }
  },
  {
    $match: {
      totalPrice: { $gt: 500 }
    }
  }
]);

Пример вывода:

[{ "_id": "Electronics", "totalPrice": 2950 }]

В этом конвейере (pipeline):

  1. Этап $group сначала вычисляет totalPrice для каждой категории.
  2. Выходные документы из этапа $group затем передаются на этап $match.
  3. Этап $match фильтрует эти документы, оставляя только те, где поле totalPrice больше ($gt) 500.

Это демонстрирует мощь конвейера агрегации, где вывод одного этапа становится входом для следующего.

Сортировка сгруппированных данных

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

Сгруппируем продукты по категориям, рассчитаем общую цену, а затем отсортируем результаты по totalPrice в порядке убывания (от наибольшего к наименьшему).

db.products.aggregate([
  {
    $group: {
      _id: "$category",
      totalPrice: { $sum: "$price" }
    }
  },
  {
    $sort: {
      totalPrice: -1
    }
  }
]);

Пример вывода:

[
  { "_id": "Electronics", "totalPrice": 2950 },
  { "_id": "Apparel", "totalPrice": 270 },
  { "_id": "Books", "totalPrice": 60 }
]

Этап $sort принимает документ, который указывает поля для сортировки и порядок сортировки:

  • totalPrice: -1: Это сортирует документы по полю totalPrice. Значение -1 указывает на порядок убывания. Для сортировки по возрастанию вы бы использовали 1.

Вы также можете сортировать по нескольким полям. Например, $sort: { category: 1, totalPrice: -1 } сначала отсортирует по названию категории в алфавитном порядке, а затем по общей цене в порядке убывания для категорий с одинаковым названием.

Изменение структуры вывода с помощью $project

Иногда формат вывода этапа $group не совсем соответствует вашим потребностям. Например, ключ группы по умолчанию называется _id. Этап $project позволяет изменять форму выходных документов, добавляя, удаляя или переименовывая поля.

Создадим конвейер, который группирует по категориям, сортирует по общей цене, а затем изменяет форму вывода, чтобы у категории было более описательное имя поля.

db.products.aggregate([
  {
    $group: {
      _id: "$category",
      totalPrice: { $sum: "$price" }
    }
  },
  {
    $sort: {
      totalPrice: -1
    }
  },
  {
    $project: {
      _id: 0,
      category: "$_id",
      total: "$totalPrice"
    }
  }
]);

Пример вывода:

[
  { "category": "Electronics", "total": 2950 },
  { "category": "Apparel", "total": 270 },
  { "category": "Books", "total": 60 }
]

Этап $project работает следующим образом:

  • _id: 0: Это исключает поле _id из вывода. По умолчанию _id всегда включается, если явно не исключено.
  • category: "$_id": Это создает новое поле с именем category и присваивает ему значение из существующего поля _id.
  • total: "$totalPrice": Это создает новое поле с именем total и присваивает ему значение из поля totalPrice.

Использование $project — это мощный способ форматирования окончательного вывода вашего конвейера агрегации для приложений или отчетов.

Резюме

В этой лабораторной работе вы научились использовать конвейер агрегации MongoDB для группировки и анализа данных. Вы начали с группировки документов с помощью оператора $group и вычисления сумм. Затем вы расширили эти знания, используя несколько аккумуляторов, таких как $avg и $sum: 1, для выполнения более сложных вычислений. Вы также научились объединять этапы агрегации, используя $match для фильтрации сгруппированных результатов, $sort для их упорядочивания и $project для преобразования окончательного вывода в чистый, читаемый формат. Это фундаментальные навыки для любого разработчика или аналитика данных, работающего с MongoDB.