Эта глава представляет подробное объяснение статистического анализа MongoDB, в основном осуществляемого через Aggregation Pipeline. Это похоже на оператор "group by" в SQL. В оболочке MongoDB статистический анализ осуществляется с использованием функции db.collection.aggregate()
.
Обучающий курс
Общие шаги
- Используйте
$match
для фильтрации целевых данных - Используйте
$group
для группировки и вычисления данных - Используйте
$sort
для сортировки результатов (необязательно)
Тестовые данные
Данные в коллекции orders
выглядят следующим образом
{ _id: 1, cust_id: "abc1", ord_date: ISODate("2012-11-02T17:04:11.102Z"), status: "A", amount: 50 }
{ _id: 2, cust_id: "xyz1", ord_date: ISODate("2013-10-01T17:04:11.102Z"), status: "A", amount: 100 }
{ _id: 3, cust_id: "xyz1", ord_date: ISODate("2013-10-12T17:04:11.102Z"), status: "D", amount: 25 }
{ _id: 4, cust_id: "xyz1", ord_date: ISODate("2013-10-11T17:04:11.102Z"), status: "D", amount: 125 }
{ _id: 5, cust_id: "abc1", ord_date: ISODate("2013-11-12T17:04:11.102Z"), status: "A", amount: 25 }
Функция aggregate
db.collection.aggregate(pipeline)
Объяснение:
-
pipeline
принимает массив в качестве параметра, где каждый элемент представляет собой этап обработки.
Пример
db.orders.aggregate([
{ $match: { status: "A" } }, // Первый этап
{ $group: { _id: "$cust_id", total: { $sum: "$amount" } } }, // Второй этап
{ $sort: { total: -1 } } // Третий этап
])
Эквивалентный SQL
select sum(amount) as total from orders
where status="A"
group by cust_id
order by total desc
Этап $match
Формат:
{ $match: { <query> } }
Объяснение:
-
<query>
- Условия запроса MongoDB
Используется для установки условий запроса. Если $match
игнорируется, это подразумевает запрос всех данных.
Совет: Если вы не знакомы с синтаксисом запросов MongoDB, пожалуйста, обратитесь к предыдущим главам.
Этап $group
Похожий на ключевое слово group by
в SQL, используется для группировки данных, после чего выполняются ряд статистических расчетов над сгруппированными данными.
Базовое использование $group
Синтаксис:
{
$group:
{
_id: <выражение>, // Условие группировки, например: по какому полю группировать
<поле1>: { <аккумулятор1> : <выражение1> }, // Операция агрегации, можно добавить N агрегационных операций
...
}
}
Объяснение:
- <поле1> - Название пользовательского статистического показателя, может быть N в общей сложности
- <аккумулятор1> - Агрегатная функция, аналогичная sum, avg и другим агрегатным функциям в SQL, отличие заключается в том, что агрегатные функции MongoDB называются с префиксом $, например: $sum, $avg
- <выражение1> - Параметр агрегатной функции, обычно это значение поля, которое нужно посчитать, ссылка на поля документа осуществляется в формате "$название поля"
Пример:
db.orders.aggregate([
{
$group: {
_id: "$cust_id",
total: { $sum: "$amount" }, // Добавить первый расчитанный показатель total, используя оператор суммирования $sum
amount_avg: {$avg: "$amount"} // Добавить второй расчитанный показатель avg, используя оператор расчета среднего значения $avg
}
}
])
Результат:
{ "_id" : "abc1", "total" : 75, "amount_avg" : 37.5 }
{ "_id" : "xyz1", "total" : 250, "amount_avg" : 83.33333333333333 }
Эквивалентный SQL:
select
sum(amount) as total,
avg(amount) as amount_avg
from orders
group by cust_id
Функции агрегации $group
Часто используемые функции агрегации для $group:
Оператор | Описание | Пример |
---|---|---|
$avg | Рассчитать среднее значение | {$avg: "$amount"} |
$sum | Суммирование | {$sum: "$amount"} |
$max | Максимальное значение | {$max: "$amount"} |
$min | Минимальное значение | {$min: "$amount"} |
$first | Вернуть данные после группировки, содержимое первого документа | {$first: "$amount"} |
$last | Вернуть данные после группировки, содержимое последнего документа | {$last: "$amount"} |
$push | Вернуть данные после группировки | { $push: { ord_date: "$ord_date", amount: "$amount" } |
$addToSet | Вернуть данные после группировки, отличается от $push тем, что удаляет дубликаты | { $addToSet: "$amount" } |
Пример $push
db.orders.aggregate(
[
{
$group:
{
_id: "$cust_id",
all: { $push: { ord_date: "$ord_date", amount: "$amount" } } // Значения полей ord_date и amount
}
}
]
)
Вывод
{ "_id" : "abc1", "all" : [ { "ord_date" : "2021-04-18 00:00:00", "amount" : 50 }, { "ord_date" : "2021-04-21 00:00:00", "amount" : 25 } ] }
{ "_id" : "xyz1", "all" : [ { "ord_date" : "2021-04-18 00:00:00", "amount" : 100 }, { "ord_date" : "2021-04-20 00:00:00", "amount" : 25 }, { "ord_date" : "2021-04-21 00:00:00", "amount" : 125 } ] }
Пример $addToSet
db.orders.aggregate(
[
{
$group:
{
_id: "$cust_id",
all_amount: { $addToSet: "$amount" } // Возвращает все уникальные значения amount
}
}
]
)
Вывод
{ "_id" : "abc1", "all_amount" : [ 25, 50 ] }
{ "_id" : "xyz1", "all_amount" : [ 100, 25, 125 ] }
$sort:
Этап $sort обычно размещается в конце для сортировки агрегированных данных.
Формат:
{ $sort: { <поле1>: <порядок сортировки>, <поле2>: <порядок сортировки> ... } }
Объяснение:
- <поле1>, <поле2> - Названия полей, которые нужно отсортировать, поддерживает несколько полей.
- <порядок сортировки> - Направление сортировки, -1 для по убыванию, 1 для по возрастанию.
Пример:
db.orders.aggregate([
{ $match: { status: "A" } },
{ $group: { _id: "$cust_id", total: { $sum: "$amount" } } },
{ $sort: { total: -1 } }
])
Агрегатная пагинация
Мы можем реализовать пагинацию с помощью операторов $limit и $skip.
Пример:
db.orders.aggregate([
{ $match: { status: "A" } },
{ $group: { _id: "$cust_id", total: { $sum: "$amount" } } },
{ $sort: { total: -1 } },
{ $limit: 5 }, // Ограничивает количество возвращаемых записей, аналогично размеру страницы в пагинации.
{ $skip: 1 } // Пропускает определенное количество записей, аналогично смещению в SQL.
])