MongoDB
агрегирование
Поиск…
Вступление
Операции Aggregations
обрабатывают записи данных и возвращают вычисленные результаты. Агрегация операций группирует значения из нескольких документов вместе и может выполнять множество операций над сгруппированными данными, чтобы вернуть один результат. MongoDB предоставляет три способа выполнения агрегации: конвейер агрегации, функцию уменьшения карты и одноцелевые методы агрегирования.
Из руководства Mongo https://docs.mongodb.com/manual/aggregation/
Синтаксис
- db.collection.aggregate (конвейер, параметры)
параметры
параметр | подробности |
---|---|
трубопровод | array (последовательность операций или этапов агрегации данных) |
опции | document (необязательно, доступно, только если конвейер представлен как массив) |
замечания
Агрегирующая структура в MongoDB используется для достижения общей функциональности SQL GROUP BY
.
В каждом примере рассмотрите следующие вставки в коллекции названных transactions
.
> db.transactions.insert({ cr_dr : "D", amount : 100, fee : 2});
> db.transactions.insert({ cr_dr : "C", amount : 100, fee : 2});
> db.transactions.insert({ cr_dr : "C", amount : 10, fee : 2});
> db.transactions.insert({ cr_dr : "D", amount : 100, fee : 4});
> db.transactions.insert({ cr_dr : "D", amount : 10, fee : 2});
> db.transactions.insert({ cr_dr : "C", amount : 10, fee : 4});
> db.transactions.insert({ cr_dr : "D", amount : 100, fee : 2});
подсчитывать
Как вы получаете количество дебетовых и кредитных транзакций? Один из способов сделать это - использовать функцию count()
как показано ниже.
> db.transactions.count({cr_dr : "D"});
или же
> db.transactions.find({cr_dr : "D"}).length();
Но что, если вы не знаете возможных значений cr_dr
. Здесь возникает задача создания системы агрегирования. См. Ниже приведенный запрос.
> db.transactions.aggregate(
[
{
$group : {
_id : '$cr_dr', // group by type of transaction
// Add 1 for each document to the count for this type of transaction
count : {$sum : 1}
}
}
]
);
И результат
{
"_id" : "C",
"count" : 3
}
{
"_id" : "D",
"count" : 5
}
сумма
Как получить суммирование amount
? См. Ниже совокупный запрос.
> db.transactions.aggregate(
[
{
$group : {
_id : '$cr_dr',
count : {$sum : 1}, //counts the number
totalAmount : {$sum : '$amount'} //sums the amount
}
}
]
);
И результат
{
"_id" : "C",
"count" : 3.0,
"totalAmount" : 120.0
}
{
"_id" : "D",
"count" : 5.0,
"totalAmount" : 410.0
}
Другая версия, которая суммирует amount
и fee
.
> db.transactions.aggregate(
[
{
$group : {
_id : '$cr_dr',
count : {$sum : 1},
totalAmount : {$sum : { $sum : ['$amount', '$fee']}}
}
}
]
);
И результат
{
"_id" : "C",
"count" : 3.0,
"totalAmount" : 128.0
}
{
"_id" : "D",
"count" : 5.0,
"totalAmount" : 422.0
}
Средний
Как получить среднюю сумму дебетовых и кредитных транзакций?
> db.transactions.aggregate(
[
{
$group : {
_id : '$cr_dr', // group by type of transaction (debit or credit)
count : {$sum : 1}, // number of transaction for each type
totalAmount : {$sum : { $sum : ['$amount', '$fee']}}, // sum
averageAmount : {$avg : { $sum : ['$amount', '$fee']}} // average
}
}
]
)
В результате
{
"_id" : "C", // Amounts for credit transactions
"count" : 3.0,
"totalAmount" : 128.0,
"averageAmount" : 40.0
}
{
"_id" : "D", // Amounts for debit transactions
"count" : 5.0,
"totalAmount" : 422.0,
"averageAmount" : 82.0
}
Операции с массивами.
Когда вы хотите работать с записями данных в массивах, вам сначала нужно развернуть массив. Операция размотки создает документ для каждой записи в массиве. Когда у вас много документов с большими массивами, вы увидите взрыв в количестве документов.
{ "_id" : 1, "item" : "myItem1", sizes: [ "S", "M", "L"] }
{ "_id" : 2, "item" : "myItem2", sizes: [ "XS", "M", "XL"] }
db.inventory.aggregate( [ { $unwind : "$sizes" }] )
Важно отметить, что когда документ не содержит массив, он будет потерян. Из mongo 3.2 и выше есть опция разматывания «preserveNullAndEmptyArrays». Этот параметр гарантирует, что документ сохраняется, когда массив отсутствует.
{ "_id" : 1, "item" : "myItem1", sizes: [ "S", "M", "L"] }
{ "_id" : 2, "item" : "myItem2", sizes: [ "XS", "M", "XL"] }
{ "_id" : 3, "item" : "myItem3" }
db.inventory.aggregate( [ { $unwind : { path: "$sizes", includeArrayIndex: "arrayIndex" } }] )
Матч
Как написать запрос, чтобы получить все отделы, где средний возраст сотрудников, составляющих менее или 70000 долларов, больше или равен 35?
Для этого нам нужно написать запрос для соответствия сотрудникам, у которых есть зарплата, которая меньше или равна 70000 долларов США. Затем добавьте совокупный этап для группировки сотрудников отделом. Затем добавьте аккумулятор с полем, например, average_age, чтобы найти средний возраст для одного отдела с помощью накопителя $ avg и ниже существующих $ match и $ group aggregates добавьте еще один агрегат $ match, чтобы мы только получали результаты со средним значением, которое больше или равно 35.
db.employees.aggregate([
{"$match": {"salary": {"$lte": 70000}}},
{"$group": {"_id": "$dept",
"average_age": {"$avg": "$age"}
}
},
{"$match": {"average_age": {"$gte": 35}}}
])
Результат:
{
"_id": "IT",
"average_age": 31
}
{
"_id": "Customer Service",
"average_age": 34.5
}
{
"_id": "Finance",
"average_age": 32.5
}
Удалите документы, которые имеют дублирующее поле в коллекции (dedupe)
Обратите внимание, что параметр allowDiskUse: true является необязательным, но поможет смягчить проблемы с памятью, поскольку это агрегирование может быть интенсивной операцией с памятью, если размер вашей коллекции большой, поэтому я рекомендую всегда использовать его.
var duplicates = [];
db.transactions.aggregate([
{ $group: {
_id: { cr_dr: "$cr_dr"},
dups: { "$addToSet": "$_id" },
count: { "$sum": 1 }
}
},
{ $match: {
count: { "$gt": 1 }
}}
],allowDiskUse: true}
)
.result
.forEach(function(doc) {
doc.dups.shift();
doc.dups.forEach( function(dupId){
duplicates.push(dupId);
}
)
})
// printjson(duplicates);
// Remove all duplicates in one go
db.transactions.remove({_id:{$in:duplicates}})