Введение
В этой лабораторной работе вы изучите основы агрегации данных в 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):
- Этап
$groupсначала вычисляетtotalPriceдля каждой категории. - Выходные документы из этапа
$groupзатем передаются на этап$match. - Этап
$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.

