Pro provádění složitějších dotazů v rámci MongoDB se doporučuje využívat agregační kanál. Jestliže jste dříve pracovali s MapReduce, zvažte přechod na agregační kanál, který je pro výpočty efektivnější.
Co je agregace v MongoDB a jak funguje?
Agregační kanál představuje vícestupňový postup pro realizaci pokročilých dotazů v MongoDB. Data jsou zpracovávána skrze jednotlivé fáze, které se nazývají trubky (anglicky „pipeline“). Výsledky z jedné fáze se mohou použít jako vstup pro další operace.
Například výstup operace vyhledání můžete přesunout do další fáze, kde data seřadíte, a tak dále, dokud nedosáhnete požadovaného výsledku.
Každá fáze agregačního kanálu obsahuje operátor MongoDB, který vytváří jeden nebo více transformovaných dokumentů. V závislosti na dotazu se může daná fáze v kanálu objevit i několikrát. Například operátory jako $count
nebo $sort
můžete v agregačním kanálu použít opakovaně.
Fáze agregačního potrubí
Agregační kanál postupně zpracovává data několika fázemi v rámci jediného dotazu. Existuje mnoho fází a jejich detailní popis naleznete v dokumentaci MongoDB.
Dále si definujeme některé z nejpoužívanějších fází.
Fáze $match
Tato fáze slouží k definování specifických podmínek pro filtrování dat před zahájením dalších agregačních kroků. Umožňuje vybrat relevantní data pro další zpracování v agregačním kanálu.
Fáze $group
Fáze $group
rozděluje data do různých skupin na základě zadaných kritérií, a to pomocí dvojic klíč–hodnota. Každá skupina je reprezentována klíčem ve výstupním dokumentu.
Jako příklad si vezměme následující data o prodejích:
S pomocí agregačního kanálu můžete spočítat celkový počet prodejů a nejvyšší prodeje pro každou sekci produktu:
{ $group: { _id: $Section, total_sales_count: {$sum : $Sold}, top_sales: {$max: $Amount}, } }
Dvojice _id: $Section
seskupí výstupní dokumenty na základě sekcí. Zadáním polí total_sales_count
a top_sales
MongoDB vytvoří nové klíče na základě operace definované agregátorem, což může být $sum
, $min
, $max
nebo $avg
.
Fáze $skip
Fáze $skip
umožňuje přeskočit definovaný počet dokumentů ve výstupu. Běžně se používá až po fázi seskupení. Pokud například očekáváte dva výstupní dokumenty, ale jeden přeskočíte, agregace vytiskne pouze druhý dokument.
Pro přidání fáze $skip
vložte tuto operaci do agregačního kanálu:
..., { $skip: 1 },
Fáze $sort
Fáze řazení ($sort
) umožňuje seřadit data vzestupně nebo sestupně. Například můžeme data z předchozího dotazu seřadit sestupně a zjistit, která sekce má nejvyšší prodeje.
Přidejte operátor $sort
do předchozího dotazu:
..., { $sort: {top_sales: -1} },
Fáze $limit
Operace limit ($limit
) snižuje počet výstupních dokumentů z agregačního kanálu. Například s pomocí $limit
získáme sekci s nejvyšším prodejem z předchozí fáze:
..., { $sort: {top_sales: -1} }, {"$limit": 1}
Výše uvedené vrátí pouze první dokument, tedy sekci s nejvyšším prodejem, která se nachází na začátku seřazeného výstupu.
Fáze $project
Fáze $project
umožňuje upravit strukturu výstupního dokumentu dle požadavků. Můžete určit, která pole mají být zahrnuta do výstupu a upravit jejich názvy.
Ukázkový výstup bez fáze $project
vypadá takto:
Podívejme se, jak to vypadá s fází $project
. Pro přidání projektu $project
do kanálu:
..., { "$project": { "_id": 0, "Section": "$_id", "TotalSold": "$total_sales_count", "TopSale": "$top_sales", } }
Vzhledem k tomu, že data byla dříve seskupena dle sekcí produktu, uvedený příklad zahrnuje každou sekci produktu ve výstupním dokumentu. Zároveň zajišťuje, že agregovaný počet prodejů a nejvyšší prodeje jsou ve výstupu označeny jako TotalSold
a TopSale
.
Výsledný výstup je ve srovnání s předchozím mnohem přehlednější:
Fáze $unwind
Fáze $unwind
rozloží pole v dokumentu na samostatné dokumenty. Například mějme následující data o objednávkách:
Použijte fázi $unwind
pro rozložení pole položek před aplikací dalších agregačních fází. Rozložení pole položek má smysl například v situaci, kdy chcete spočítat celkový příjem pro každý produkt:
db.Orders.aggregate([ { "$unwind": "$items" }, { "$group": { "_id": "$items.product", "total_revenue": { "$sum": { "$multiply": ["$items.quantity", "$items.price"] } } } }, { "$sort": { "total_revenue": -1 } }, { "$project": { "_id": 0, "Product": "$_id", "TotalRevenue": "$total_revenue", } } ])
Zde je výsledek výše uvedeného agregačního dotazu:
Jak vytvořit agregační kanál v MongoDB
Ačkoli agregační kanál zahrnuje několik operací, výše uvedené fáze vám poskytnou základní představu o jejich použití v rámci kanálu, včetně jednoduchého dotazu pro každou z nich.
Na základě dřívějších dat o prodejích si ukažme některé z uvedených fází v jednom celku, abychom získali širší pohled na agregační kanál:
db.sales.aggregate([ { "$match": { "Sold": { "$gte": 5 } } }, { "$group": { "_id": "$Section", "total_sales_count": { "$sum": "$Sold" }, "top_sales": { "$max": "$Amount" }, } }, { "$sort": { "top_sales": -1 } }, {"$skip": 0}, { "$project": { "_id": 0, "Section": "$_id", "TotalSold": "$total_sales_count", "TopSale": "$top_sales", } } ])
Konečný výstup bude vypadat podobně jako dříve:
Agregační kanál vs. MapReduce
Až do ukončení podpory v MongoDB 5.0 byl tradičním způsobem agregace dat v MongoDB MapReduce. Přestože má MapReduce širší uplatnění i mimo MongoDB, je méně efektivní než agregační kanál a vyžaduje skriptování třetích stran pro samostatné psaní mapovacích a redukčních funkcí.
Agregační kanál je naproti tomu specifický pouze pro MongoDB. Poskytuje ovšem přehlednější a efektivnější způsob provádění složitých dotazů. Kromě jednoduchosti a škálovatelnosti dotazů umožňují jednotlivé fáze kanálu lepší přizpůsobení výstupu.
Mezi agregačním kanálem a MapReduce je mnoho dalších rozdílů. Uvidíte je při přechodu z MapReduce na agregační kanál.
Zefektivněte dotazy na velká data v MongoDB
Pokud chcete provádět hloubkové výpočty na komplexních datech v MongoDB, měl by být váš dotaz maximálně efektivní. Agregační kanál je ideální pro pokročilé dotazování. Místo manipulace s daty v samostatných operacích, které často snižují výkon, vám agregace umožňuje sloučit všechny operace do jednoho výkonného kanálu a provést je najednou.
Ačkoli je agregační kanál efektivnější než MapReduce, můžete agregaci zrychlit a zefektivnit indexováním dat. Tím se omezí množství dat, které MongoDB musí prohledávat během každé fáze agregace.