MongoDB - grupowanie - Instytut Informatyki Teoretycznej i

Transkrypt

MongoDB - grupowanie - Instytut Informatyki Teoretycznej i
MongoDB - grupowanie
Technologie zarządzania treścią
dr inż. Robert Perliński
[email protected]
Politechnika Częstochowska
Instytut Informatyki Teoretycznej i Stosowanej
4 listopada 2016
Plan wykładu
1
Agregacje
Strumień agregacji
Operatory arytmetyczne i akumulujące
Map-Reduce
Proste metody agregacyjne
Polecenia agregacyjne
2
Źródła
MongoDB - grupowanie
2/52
Rodzaje agregacji w bazach dokumentów
Operacje agregacji przetwarzają dokumenty i zwracają przeliczone wyniki.
Agregacje:
grupują w jedną wartości z różnych dokumentów,
wykonują wiele różnych operacji na zgrupowanych danych,
zwracając pojedynczy wynik.
MongoDB dostarcza trzy sposoby przeprowadzania agregacji:
strumień/potok agregacji (ang. aggregation pipeline)
map-reduce
metody agregacyjne pojedynczego zastosowania (ang. single purpose
aggregation methods).
MongoDB - grupowanie
3/52
Potok agregacji
Strumień, potok agregacji:
specjalny szablon do przeprowadzania agregacji,
dostępny w MongoDB od wersji 2.2,
wzorowany na strumieniowym przetwarzaniu danych,
dokumenty przechodzą przez wieloetapowy proces, który je
przekształca.
Możliwe operacje:
filtrowanie - wybór dokumentów (zapytania), zmiana ich formy
(transformacje),
grupowanie i sortowanie według wybranych pól, również tablic,
na poszczególnych etapach można używać operatorów do różnych
zadań, np. średnia, łączenie napisów ...
MongoDB - grupowanie
4/52
Potok agregacji
Potok agregacji:
jest efektywna metodą agregowania danych, preferowaną
używa wbudowanych w MongoDB operacji,
działa również na klastrach, na kolekcjach rozproszonych,
może używać indeksów dla zwiększenia wydajności w niektórych
etapach przetwarzania potokowego,
posiada wewnętrzną fazę optymalizacji.
MongoDB - grupowanie
5/52
Przykład potoku agregacji
MongoDB - grupowanie
6/52
Potok agregacji
Strumień agregacji składa się z etapów.
Każdy z etapów przetwarza dokumenty, które przechodzą przez cały potok.
Nie ma konieczności produkowania tylu dokumetów wyjściowych ile jest
dokumentów wejściowych; niektóre etapy mogą zwracać nowe dokumenty
albo filtrować zwracane dokumenty.
Etapy mogą pojawiać się wiele razy w cały potoku przetwarzania.
Strumień agregacji dostępny jest poprzez:
metodę db.kolekcja.aggregate()
polecenie aggregate()
MongoDB - grupowanie
7/52
Operatory potoku agregacji
W metodzie db.kolekcja.aggregate() etapy w przetwarzaniu
strumienia agregacji są zapisywane jako dokumenty w tablicy:
db.kolekcja.aggregate( [ {etap}, ... ] )
W każdym etapie agregacji dostępne są specjalne operatory, które są
wykorzystywane do budowy wyrażeń. Wyrażenia operatorowe są podobne
do funkcji przyjmujących argumenty. Przeważnie wyrażenia te przyjmują
tablicę argumentów i mają formę:
{ operator: [ argument1, argument2, ... ] }
Dla operatora jednoargumentowego opuszcza się tablicę:
{ operator: argument }
MongoDB zawiera wiele operatorów grupujących i arytmetycznych do
wykrzystania w potoku agregacji.
MongoDB - grupowanie
8/52
Operatory arytmetyczne
$abs - zwraca wartośc bezwzględną liczby,
$add - dodaje liczby zwracając sumę albo dodaje liczby i datę zwracając nową
datę; liczby sumowane do daty oznaczają milisekundy,
$ceil - najmniejsza liczba całkowita większa od danej,
$floor - największa liczba całkowita mniejsza od danej,
$divide - wynik dzielenia, przyjmuje dwa parametry,
$exp - wynik podniesienia e do podanej potęgi,
$ln - liczy logarytm naturalny podanej liczby,
$log - liczy logarytm podaje liczby przy podanej bazie, przyjmuje dwa parametry,
$log10 - liczy logarytm dziesiętny,
$mod - reszta z dzielenia, przyjmuje dwa parametry,
$multiply - zwraca wynik mnożenia dowolnej liczby argumentów,
$pow - podnosi liczbę do określonej potęgi,
$sqrt - liczy pierwiastek kwadratowy,
$substract - odejmuje dwie liczby, dwie daty albo liczbę od daty,
$trunc - przekształca liczbę na liczbę całkowitą.
MongoDB - grupowanie
9/52
Operatory akumulujące
Lista operatorów akumulujących:
$sum - zwraca sumę wartości liczbowych; ignoruje wartości nieliczbowe,
$avg - zwraca średnią wartości liczbowych; ignoruje wartości nieliczbowe,
$first - zwraca wartość z pierwszego dokumentu z każdej grupy; dokumenty są
uporządkowane tylko, jeśli zostały wcześniej uporządkowane,
$last - zwraca wartość z ostatniego dokumentu z każdej grupy; dokumenty są
uporządkowane tylko, jeśli zostały wcześniej uporządkowane,
$max - zwraca największą wartość z każdej grupy,
$min - zwraca najmniejszą wartość z każdej grupy,
$push - zwraca tablicę wartości uzyskanych wedłuż wyrażenia z każdego
dokumentu z grupy,
$addToSet - zwraca tablicę unikalnych wartości określonych w wyrażeniu z każdej
grupy; kolejność elementów w tablicy jest nieokreślona,
$stdDevPop - odchylenie standardowe liczone z całej populacji z wejściwych
wartości z każdej grupy,
$stdDevSamp - odchylenie standardowe na podstawie próbki, generalizowane na
całość danych.
MongoDB - grupowanie
10/52
Operatory potoku agregacji I
$project - Modyfikuje każdy dokument w potoku agregacji dodając
nowe pola lub usuwając istniejące. Zwraca jeden dokument wyjściowy
dla każdego dokumentu wejściowego.
$match - Filtruje strumień dokumentów pozwalając na przejście dalej
tylko dopasowanym dokumentom, tym, które spełniają warunek.
$match używa standardowych zapytań MongoDB. Dla każdego
dokumentu wejściowego zwraca taki sam dokument (w przypadku
dopasowania) albo nie zwraca dokumentu (brak dopasowania).
$redact - Modyfikuje każdy dokument w strumieniu poprzez
ograniczanie zawartości każdego dokumentu opierając się na
wewnętrznej zawartośći tego samego dokumentu. Używa
funkcjonalności $project i $match. Może być użyty w celu redakcji
dokumentu na poziomie pól. Dla każdego dokumentu wejściowego
zwraca jeden albo zero dokumentów.
MongoDB - grupowanie
11/52
Baza 50 osób
// Dane pierwszej osoby w bazie
{
"_id" : "566893bd2ae04f8923cb23c3",
"index" : 0,
"zatrudniony" : true,
"stanKonta" : 1833.19,
"wiek" : 21,
"oczy" : "niebieskie",
"nazwa" : {
"imie" : "Keri",
"nazwisko" : "Hubbart"
},
"firma" : "FUTURIS",
"email" : "[email protected]",
"telefon" : "+1 (887) 496-3887",
"adres" : "117 Boynton Place, Gwynn, Wisconsin, 3666",
"przyjaciele" : [
{ "id" : 0, "nazwa" : "Gregory Delaney" },
{ "id" : 1, "nazwa" : "Morse Lawson" },
{ "id" : 2, "nazwa" : "Ross Baldwin" }
],
"ulubionyOwoc" : "jabłka"
}
MongoDB - grupowanie
12/52
Przykład projekcji I
// projekcja, przekazuje dalej tylko wiek i nazwę osoby czyli wybrane pola
db.osoby.aggregate( [ { $project: { _id:0, nazwa:1, wiek:1 } } ] )
// wynik zwierający wszystkie dokumenty z bardzo okrojoną zawartością pól
{
"result" : [
{
"wiek" : 21,
"nazwa" : {
"imie" : "Keri",
"nazwisko" : "Hubbard"
}
},
{
"wiek" : 42,
"nazwa" : {
"imie" : "Corine",
"nazwisko" : "Koch"
}
},
...
],
"ok" : 1
}
MongoDB - grupowanie
13/52
Przykład projekcji II
// projekcja, jedno dodatkowe pole "kontoPoDodatku"
db.osoby.aggregate(
[ { $project: {
_id: 0,
nazwa: 1,
stanKonta: 1,
kontoPoDodatku: { $add: [ "$stanKonta",
}
} ] )
// wynik: wszystkie dokumenty, okrojone pola, jedno
{
"result" : [
{
"stanKonta" : 1833.19,
"nazwa" : { "imie" : "Keri", "nazwisko"
"kontoPoDodatku" : 2473.19
}, ...
{
"stanKonta" : 1311.41,
"nazwa" : { "imie" : "Jo", "nazwisko" :
"kontoPoDodatku" : 1951.41
}
], "ok" : 1
}
MongoDB - grupowanie
z sumą wartości
640 ] }
nowe pole
: "Hubbard" },
"Kane" },
14/52
Przykład operatora $match
// ogranicznie dokumentów do tych spełniających warunek, przechodzą tylko
// dokumenty, w których osoby mają więcej niż 66 lat, są 3 takie dokumenty
db.osoby.aggregate( [ { $match: { wiek: { $gt:66 } } } ] )
{
"result" : [
{
"_id" : "566893bd01f4489524f9b004",
"index" : 15, "zatrudniony" : false,
"stanKonta" : 1331.36, "wiek" : 67,
...
}, {
"_id" : "566893bdbf16699ed211e939",
"index" : 33, "zatrudniony" : true,
"stanKonta" : 6563.59, "wiek" : 70,
...
}, {
"_id" : "566893bd981679da93026dd0",
"index" : 45, "zatrudniony" : false,
"stanKonta" : 7644, "wiek" : 70,
...
}
], "ok" : 1
}
MongoDB - grupowanie
15/52
Operatory potoku agregacji II
$limit - Przekazuje pierwszych n dokumentów w niezmodyfikowanej
formie dalej. Dla każdego dokumentu wejściowego zwraca jeden (dla
pierwszych n dokumentów) albo zero dokumentów (po n pierwszych).
$skip - Opuszcza n pierwszych elementów przekazując pozostałe w
niezmienionej formie dalej do strumienia. Dla każdego dokumentu
wejściowego zwraca zero (dla pierwszych n dokumentów) albo jeden
dokument (po n pierwszych dokumentach).
$sort - Porządkuje dokumenty w strunieniu według określonego
klucza. Zmienia się tylko ich kolejność. Same dokumenty nie ulegają
zmianie. Dla każdego dokumentu wejściowego zwracany jest
dokument wyjściowy.
$sample - Wybiera losowo określoną liczbę dokumentów wejściowych.
MongoDB - grupowanie
16/52
Przykład - $limit i $skip
db.osoby.find({},{_id:0,index:1})
{ "index" : 0 }
{ "index" : 1 }
{ "index" : 2 }
{ "index" : 3 }
{ "index" : 4 }
{ "index" : 5 }
...
{ "index" : 49 }
db.osoby.aggregate(
{
"result" : [
{
"index"
}, {
"index"
}, {
"index"
}
],
"ok" : 1
}
MongoDB - grupowanie
[ {$limit:6}, {$skip:3}, {$project:{_id:0,index:1}} ] )
: 3
: 4
: 5
17/52
Przykład - $limit i $skip - inna kolejność
db.osoby.aggregate( [ {$skip:3}, {$limit:6}, {$project:{_id:0,index:1}} ] )
{
"result" : [
{
"index"
}, {
"index"
}, {
"index"
}, {
"index"
}, {
"index"
}, {
"index"
}
],
"ok" : 1
: 3
: 4
: 5
: 6
: 7
: 8
}
MongoDB - grupowanie
18/52
Przykład losowych danych ($sample)
// trzy losowe dokumenty razem z projekcją
// $sample działa od wersji 3.2 - przykład spreparowany
db.osoby.aggregate( [
{ $sample: { $size:3 } },
{ $project: { _id:0, index:1 } }
] )
{
"result" : [
{
"index" : 45
}, {
"index" : 2
}, {
"index" : 18
}
],
"ok" : 1
}
MongoDB - grupowanie
19/52
Przykład sortowania danych I
// sortowanie po nazwie firmy
db.osoby.aggregate( [
{ $sort: { wiek:1, firma:1 } },
{ $project: { _id:0, wiek:1, firma:1 } }
] )
{
"result" : [
{ "wiek"
{ "wiek"
{ "wiek"
{ "wiek"
...,
{ "wiek"
{ "wiek"
{ "wiek"
{ "wiek"
...,
{ "wiek"
{ "wiek"
{ "wiek"
],
"ok" : 1
:
:
:
:
20,
21,
21,
24,
"firma"
"firma"
"firma"
"firma"
:
:
:
:
"ZBOO" },
"COMVEYER" },
"FUTURIS" },
"CORPORANA" },
:
:
:
:
61,
61,
61,
61,
"firma"
"firma"
"firma"
"firma"
:
:
:
:
"GRAINSPOT" },
"OMNIGOG" },
"OPTYK" },
"ZOLAVO" },
: 67, "firma" : "WARETEL" },
: 70, "firma" : "DYMI" },
: 70, "firma" : "GAZAK" }
}
MongoDB - grupowanie
20/52
Przykład sortowania danych II
// sortowanie po utworzonym przez projekcję polu wiekKonto
db.osoby.aggregate( [
{ $project: {
_id:0, index:1, wiek:1, stanKonta:1,
wiekKonto: { $multiply: [ "$wiek", "$stanKonta" ] } } },
{ $sort: { wiekKonto:1 } }
] )
{
"result" : [
{
"index" : 13, "stanKonta" : 1106.4, "wiek" : 21,
"wiekKonto" : 23234.4
}, {
"index" : 0, "stanKonta" : 1833.19, "wiek" : 21,
"wiekKonto" : 38496.99
},
...,
{
"index" : 45, "stanKonta" : 7644, "wiek" : 70,
"wiekKonto" : 535080
}
], "ok" : 1
}
MongoDB - grupowanie
21/52
Operatory potoku agregacji III
$group - Grupuje dokumenty wejściowe według określonego
wyrażenia i stosuje do nich wyrażenie agregujące, jeśli takie określono,
do każdej grupy. Pobiera wszystkie dokumenty wejściowe i zwraca
jeden dokument dla każdej grupy. Dokumenty wyjściowe zawierają
tylko pole identyfikujące i, jeśli określono, pola agregujące.
$unwind - Przekształca dokumenty wejściowe zawierające tablice na
n dokumentów wyjściwych. n jest liczbą elementów tablicy. W każdym
dokumencie wyjściowym tablica jest zastąpioną jedną z jej wartości.
Dla każdego dokumentu wejściowego zwraca n dokumentów, gdzie n
jest liczbą elementów tablicy i może być zerem dla pustych tablic.
$out - Zapisuje wynikowe dokumenty strumienia agregacji w kolekcji.
Używanie operatora $out (tego etapu) wymaga żeby był to ostatni
etap w strumieniu.
MongoDB - grupowanie
22/52
Przykład grupowania I
// grupowanie po ulubionym owocu, liczba osób w każdej grupie
db.osoby.aggregate( [
{$group:{_id:"$ulubionyOwoc", liczba:{$sum:1}}}
] )
{ "result" : [
{
"_id" : "truskawki",
"liczba" : 9
}, {
"_id" : "winogrona",
"liczba" : 6
}, {
"_id" : "babany",
"liczba" : 19
}, {
"_id" : "wiśnie",
"liczba" : 8
}, {
"_id" : "jabłka",
"liczba" : 8
}
], "ok" : 1
}
MongoDB - grupowanie
23/52
Przykład grupowania II
// grupowanie po ulubionym owocu, sumowanie w grupie stanu konta
db.osoby.aggregate( [
{$group:{_id:"$ulubionyOwoc", gotowka:{$sum:"$stanKonta"}}}
] )
{ "result" : [
{
"_id" : "truskawki",
"gotowka" : 47653.030000000006
}, {
"_id" : "winogrona",
"gotowka" : 42679.48
}, {
"_id" : "babany",
"gotowka" : 83664.53
}, {
"_id" : "wiśnie",
"gotowka" : 30159.78
}, {
"_id" : "jabłka",
"gotowka" : 24684.95
}
], "ok" : 1
}
MongoDB - grupowanie
24/52
Przykład grupowania i operator $push
// grupowanie po wieku, pole stanKonta zawiera tablicę zawierającą
// stany kont grupy, pole sumaNaKontach zawiera wartość sumy stanu kont
db.osoby.aggregate([
{
$group:{
_id: "$wiek",
owoce: { $push: "$ulubionyOwoc" },
stanKonta: { $push: "$stanKonta" },
sumaNaKontach: { $sum: "$stanKonta" }
}
}
])
{
"result" : [
{
"_id" : 44, "owoce" : [ "jabłka" ],
"stanKonta" : [ 2281.48 ],
"sumaNaKontach" : 2281.48
}, ..., {
"_id" : 38, "owoce" : [ "truskawki", "babany", "truskawki" ],
"stanKonta" : [ 5694.91, 6590.91, 1311.41 ],
"sumaNaKontach" : 13597.23
}, ...
], "ok" : 1
}
MongoDB - grupowanie
25/52
Przykład grupowania i operator $out
// operator $out (od wer. 2.6) - dane wyjściowe zapisywane w osobnej kolekcji
db.osoby.aggregate([
{
$group:{
_id: "$wiek",
owoce: { $push: "$ulubionyOwoc" },
stanKonta: { $push: "$stanKonta" },
sumaNaKontach: { $sum: "$stanKonta" }
}
},
{ $out: "owocoweKonta" }
])
db.owocoweKonta.find()
{ "_id" : 44, "owoce" : [ "jabłka" ],
"stanKonta" : [ 2281.48 ], "sumaNaKontach" : 2281.48 }
{ "_id" : 20, "owoce" : [ "winogrona" ],
"stanKonta" : [ 7795.62 ], "sumaNaKontach" : 7795.62 }
{ "_id" : 36, "owoce" : [ "truskawki" ],
"stanKonta" : [ 7841.4 ], "sumaNaKontach" : 7841.4 }
{ "_id" : 57, "owoce" : [ "babany" ],
"stanKonta" : [ 5302.23 ], "sumaNaKontach" : 5302.23 }
{ "_id" : 70, "owoce" : [ "truskawki", "truskawki" ],
"stanKonta" : [ 6563.59, 7644 ], "sumaNaKontach" : 14207.59 }
MongoDB - grupowanie
26/52
Przykład operatora $unwind - dane do rozwinięcia
// jeden dokument po projekcji, zawiera tablicę przyjaciele
db.osoby.aggregate( [
{ $project: { _id:0, index:1, przyjaciele:1 } },
{ $limit:1 }
] )
{
"result" : [
{
"index" : 0,
"przyjaciele" : [
{
"id" : 0, "nazwa" : "Gregory Delaney"
},
{
"id" : 1, "nazwa" : "Morse Lawson"
},
{
"id" : 2, "nazwa" : "Ross Baldwin"
}
]
}
], "ok" : 1
}
MongoDB - grupowanie
27/52
Przykład operatora $unwind
// rozwinięcie dokumentu według pól tablicy przyjaciele
db.osoby.aggregate( [
{ $project: { _id:0, index:1, przyjaciele:1 } },
{ $limit:1 },
{ $unwind: "$przyjaciele" }
] )
{
"result" : [
{
"index" : 0,
"przyjaciele" : { "id" : 0, "nazwa" : "Gregory Delaney" }
},
{
"index" : 0,
"przyjaciele" : { "id" : 1, "nazwa" : "Morse Lawson" }
},
{
"index" : 0,
"przyjaciele" : { "id" : 2, "nazwa" : "Ross Baldwin" }
}
], "ok" : 1
}
MongoDB - grupowanie
28/52
Operatory potoku agregacji IV
$geoNear - Zwraca uporządkowany zbiór dokumentów według
odległości od punktu na sferze. Używa funkcjonalności $match,
$sort oraz $limit dla danych przestrzennych. Dane wyjściowe
zawierają dodatkowe pole określające odległość; mogą zawierać też
pole z położeniem.
$lookup - Wykonuje lewostronne złączenie zewnętrzne z inną
kolekcją w tej samej bazie danych w celu umożliwienia filtrowania
dokumentów z dołączonej kolekcji. Dopiero od wersji 3.2.
$indexStats - Zwraca statystyki odnośnie użycia każdego indeksu w
kolekcji.
MongoDB - grupowanie
29/52
Przykład operatora $lookup
// kolekcja zamowienia
{ "_id" : 1, "pozycja" : "abc", "cena" : 12, "ilosc" : 2 }
{ "_id" : 2, "pozycja" : "jkl", "cena" : 20, "ilosc" : 1 }
{ "_id" : 3 }
// kolekcja spis
{ "_id" : 1, "sku"
{ "_id" : 2, "sku"
{ "_id" : 3, "sku"
{ "_id" : 4, "sku"
{ "_id" : 5, "sku"
{ "_id" : 6 }
:
:
:
:
:
"abc", opis: "produkt 1",
"def", opis: "produkt 2",
"ijk", opis: "produkt 3",
"jkl", opis: "produkt 4",
null, opis: "Niekomletny"
"na
"na
"na
"na
}
składzie"
składzie"
składzie"
składzie"
:
:
:
:
120 }
80 }
60 }
70 }
db.zamowienia.aggregate([ {
$lookup: {
from: "spis",
localField: "pozycja",
foreignField: "sku",
as: "dokumenty_spisu"
}
} ])
MongoDB - grupowanie
30/52
Przykład operatora $lookup
{
"_id" : 1,
"pozycja" : "abc",
"cena" : 12, "ilosc" : 2,
"dokumenty_spisu" : [
{ "_id" : 1, "sku" : "abc", opis: "produkt 1", "na składzie" : 120 }
]
}
{
"_id" : 2,
"pozycja" : "jkl",
"cena" : 20, "ilosc" : 1,
"dokumenty_spisu" : [
{ "_id" : 4, "sku" : "jkl", "opis" : "produkt 4", "na składzie" : 70 }
]
}
{
"_id" : 3,
"dokumenty_spisu" : [
{ "_id" : 5, "sku" : null, "opis" : "Niekomletny" },
{ "_id" : 6 }
]
}
MongoDB - grupowanie
31/52
Map-Reduce
MongoDB pozwala na użycie operacji map-reduce do wykonania agregacji.
Map-Reduce składa się z dwóch faz:
fazy mapowania (ang. map stage) - przetwarza dokumenty zwracając
jeden lub więcej obiektów dla każdego dokumentu wejściowego,
faze redukcji (ang. reduce stage) - łączy/zbiera wyniki uzyskane z
fazy mapowania.
Map-Reduce może mieć jeszcze fazę zakończenia, w której dokonywane są
modyfikacje danych wyjściowych.
MongoDB - grupowanie
32/52
Map-Reduce
Map-Reduce:
umożliwia podanie warunków zapytania określających wybrane
dokumenty,
umożliwia sotrowanie czy ograniczanie wyników wyjściowych, np.
poprzez limit(),
może operować na klastrach, szczególnie przy bardzo dużej ilości
danych jest to właściwa metoda,
wyniki również mogą być zapisywane w klastrach, w rozproszonej
kolekcji,
generalnie rzecz biorąc jest mniej efektywne i bardziej skomplikowane
niż strumień agregacji.
MongoDB - grupowanie
33/52
Przykład map-reduce
MongoDB - grupowanie
34/52
Przykład map-reduce
db.osoby.mapReduce(
function() { emit( this.oczy, this.wiek); },
function(key, values) { return Array.sum(values) },
{
query: {zatrudniony:true}, // zwraca 30 dokukmentów z 50
out: "lataPoOczach"
// kolekcja wyjściowa
}
)
{
"result" : "lataPoOczach",
"timeMillis" : 571,
"counts" : {
"input" : 30,
"emit" : 30,
"reduce" : 3,
"output" : 3
}, "ok" : 1,
}
db.lataPoOczach.find()
{ "_id" : "brązowe", "value" : 694 }
{ "_id" : "niebieskie", "value" : 294 }
{ "_id" : "zielone", "value" : 333 }
MongoDB - grupowanie
35/52
Odpowiednik ze strumienia agregacji
db.osoby.aggregate(
{ $match: { zatrudniony:true } },
{ $group: { _id:"$oczy", value: { $sum:"$wiek" } } },
{ $out:"lataPoOczach2" }
)
db.lataPoOczach2.find()
{ "_id" : "zielone", "value" : 333 },
{ "_id" : "brązowe", "value" : 694 },
{ "_id" : "niebieskie", "value" : 294 }
MongoDB - grupowanie
36/52
Metody agregacyjne pojedynczego zastosowania
Oprócz strumienia agregacji i map-reduce MongoDB udostępnia trzy
proste operacje służące agregacji:
db.kolekcja.count()
db.kolekcja.group()
db.kolekcja.distinct()
Każda z tych operacji agreguje dokumenty z jednej kolekcji. Komendy
ułatwiają prosty dostęp do najczęstszych poleceń agregacyjnych, jednak
nie posiadają takiej elestyczności i możliwości jak sturmień agregacji czy
map-reduce.
Wszystkie przedstawione metody agregacji można wywołać alternatywnie
korzystając z poleceń agregacyjnych.
MongoDB - grupowanie
37/52
Polecenia agregacyjne
MongoDB zawiera pięć poleceń agregacyjnych:
aggregate - wykonuje różne agregacje, np. grupowanie korzystając z
podoku agregacji,
count - zlicza liczbę dokumentów w kolekcji,
distinct - wyświetla niepowtarzające się wartości z podanego klucza w
kolekcji,
group - grupuje dokumenty w kolekcji po określonym kluczu i
wykonuje prostą agregację,
mapReduce - wykonuje agregację map-reduce na dużych zbiorach
danych.
Polecenie:
db.runCommand({ aggregate: "kolekcja", pipeline: [ etap1,etap2,... ] })
odpowiada
db.kolekcja.aggregate( [ { etap1,etap2,... ] )
MongoDB - grupowanie
38/52
Metoda count()
db.kolekcja.count(zapytanie, opcje)
Polecenie jest równoważne:
db.kolekcja.find(zapytanie).count()
Metoda zwraca liczbę dokumentów, które spełniają zapytanie.
Zamiast zwracać pasujące dokumenty jak metoda find(), count()
zwraca tylko ich liczbę.
Parametr opcje zmieniający działanie zapytania nie jest obowiązkowy.
Niektóre opcje:
limit - maksymalna liczba dokumentów, które mają być liczone,
skip - liczba dokumentów, które trzeba opuścić przed liczeniem,
maxTimeMS - maksymalny czas poświęcony na zliczanie
MongoDB - grupowanie
39/52
Metoda count() - przykłady
db.osoby.count() // liczba wszystkich osób, 50 osób
db.osoby.find().count()
// j.w.
db.runCommand({count:’osoby’}) // j.w.
// liczba osób starszych niż 35 lat, 37 osób
db.osoby.count({wiek:{$gt:35}})
db.osoby.find({wiek:{$gt:35}}).count()
db.runCommand({count:’osoby’,query:{wiek:{$gt:35}}})
// j.w.
// j.w.
// nie działa w wersji 2.4.5, zwraca liczbę osób 37
db.osoby.count({wiek:{$gt:35}},{limit:30})
//j.w.-limit nie działa
db.osoby.find({wiek:{$gt:35}}).limit(30).count() //j.w.
// działa, zwraca liczbę osób 30
db.runCommand({count:’osoby’,query:{wiek:{$gt:35}},limit:30})
// zwraca liczbę osób 17
db.runCommand({count:’osoby’,query:{wiek:{$gt:35}},limit:50,skip:20})
MongoDB - grupowanie
40/52
Metoda group()
db.kolekcja.group(
{key, reduce, initial [, keyf] [, cond] [, finalize] }
)
Metoda group():
grupuje dokumenty w kolekcji po określonych kluczach (key),
wykonuje proste funkcje agregacyjne jak liczenie czy sumowanie,
jest analogiczna do SELECT ... GROUP BY w języku SQL,
zwraca tablicę (maksymalnie 20000 elementów),
nie działa w środowisku rozproszonym; trzeba używać potoku
agregacji albo map-reduce,
dokument wynikowy nie może mieć więcej niż 16 MB (maksymalny
dokument BSON).
MongoDB - grupowanie
41/52
Metoda group()
db.kolekcja.group(
{key, reduce, initial [, keyf] [, cond] [, finalize] }
)
Pole
key
Typ
dokument
reduce
funkcja
initial
keyf
dokument
funkcja
cond
dokument
finalize
funkcja
MongoDB - grupowanie
Opis
Pole lub pola, po których będzie grupowanie. Zwraca ”obiekt klucza”,
po którym grupujemy.
Funkcja agregacyjna, która działa na dokumentach podczas operacji grupowania. Funkcje mogą zwracać sumę albo liczbę elementów.
Przyjmują dwa parametry: bieżący dokument oraz dokument będący
wynikiem agregacji dla tej grupy.
Inicjalizuje dokument będący wynikiem agregacji.
Alternatywa dla parametru key. Określa funkcję, która tworzy ”obiekt
klucza” używanego do grupowania. Pola keyf używa się zamiast key
aby grupować po polach uzyskanych z obliczeń zamiast tych istniejących w dokumencie.
Określa, które dokumenty z kolekcji mają być przetwarzane. Opuszczenie tego parametru spowoduje grupowanie na bazie wszystkich dokumentów.
Funkcja przetwarza każdy element wynikowy zanim metod group()
zwróci ostateczny wynik. Może ona modyfikować dokument wynikowy
albo go zastępować.
42/52
Metoda group() - przykłady
// zwraca tablicę 24 grup z różnymi wartościami wieku osób
db.osoby.group( { key:{wiek:1}, reduce: function(curr,result){}, initial:{}})
[
{ "wiek" : 21 }, { "wiek" : 42 }, ..., { "wiek" : 44 }
]
// tablica pogrupowana po wieku z liczbą elementów w grupie
db.osoby.group({
key:{wiek:1},
reduce: function(curr,result){
result.liczba+=1
},
initial:{ liczba:0 }
})
[
{ "wiek" : 21, "liczba" : 2 },
{ "wiek" : 42, "liczba" : 5 },
...
{ "wiek" : 44, "liczba" : 1 }
]
MongoDB - grupowanie
43/52
Metoda group() - przykłady
// suma stanu konta w grupach utworzonych według wieku,
// wyświetlono też liczbę osób w grupie
db.osoby.group({
key:{wiek:1},
reduce: function(curr,result) {
result.liczba+=1;
result.sumaStanuKonta+=curr.stanKonta
},
initial:{sumaStanuKonta:0, liczba:0}
})
[
{ "wiek" : 21, "sumaStanuKonta" : 2939.59, "liczba" : 2 },
{ "wiek" : 42, "sumaStanuKonta" : 27484.36, "liczba" : 5 },
...,
{ "wiek" : 44, "sumaStanuKonta" : 2281.48, "liczba" : 1 }
]
MongoDB - grupowanie
44/52
Metoda group() - przykłady
// średni stan konta w grupach utworzonych według wieku,
// wyświetlono też liczbę osób w grupie
db.osoby.group({
key:{wiek:1},
reduce: function(curr,result) {
result.liczba+=1;
result.sredniStanKonta+=curr.stanKonta
},
initial:{sredniStanKonta:0, liczba:0},
finalize:function(result) {
result.sredniStanKonta=result.sredniStanKonta/result.liczba
}
})
[
{ "wiek" : 21, "sredniStanKonta" : 1469.795, "liczba" : 2 },
{ "wiek" : 42, "sredniStanKonta" : 5496.872, "liczba" : 5 },
...
{ "wiek" : 44, "sredniStanKonta" : 2281.48, "liczba" : 1 }
]
MongoDB - grupowanie
45/52
Metoda distinct()
db.kolekcja.distinct(pole, zapytanie)
Metoda distinct():
znajduje w jednej kolekcji niepowtarzające się wartości dla
określonego pola,
zwraca wyniki w postaci tablicy.
Parametry:
pole - pole, na bazie którego mają być zwrócone niepowtarzające się
wartości,
zapytanie - określa, które dokumenty z kolekcji mają być
uzwględnione w wyszukiwaniu niepowtarzających się wartości.
Jeśli pole jest tablicą, metoda distinct() rozważy każdy jej element
jako osobną wartość.
Metoda distinct() używa indeksów, jeśli jest to możliwe.
Możliwe jest też całkowite ”pokrywanie” metody przez indeks.
MongoDB - grupowanie
46/52
Przykład metody distinct()
MongoDB - grupowanie
47/52
Metoda distinct() - przykłady
db.osoby.distinct()
// bez argumentów - wynik to pusta tablica [ ]
db.osoby.distinct("zatrudniony") // wynik: [ true, false ]
db.osoby.distinct("wiek")
[ 21,42,59,25,35,33,61,52,65,32,53,67,58,
50,34,37,43,29,49,38,51,70,57,36,24,20,44 ]
db.osoby.distinct("wiek").sort()
[ 20,21,24,25,29,32,33,34,35,36,37,38,42,43,
44,49,50,51,52,53,57,58,59,61,65,67,70 ]
db.osoby.distinct("wiek",{wiek:{$gt:42}})
[ 59, 61, 52, 65, 53, 67, 58, 50, 43, 49, 51, 70, 57, 44 ]
db.osoby.distinct("oczy",{oczy:{$regex:/ie/i}}) // napis zawierający "ie"
[ "niebieskie", "zielone" ]
// nie ma brązowych
db.resteuracje.distinct("adres.ulica") // lista ulic z restauracjami
[ ..., "Nelson Ave", "W 13Th St", "W 15Th St", "E 48Th St" ]
db.resteuracje.distinct("adres.ulica").length // liczba ulic
2790
MongoDB - grupowanie
48/52
Polecenie distinct
Składnia polecenia distinct:
{distinct: "kolekcja", key: "pole", query: zapytanie}
Pole
distinct
key
query
Typ
string
string
dokument
Opis
Nazwa kolekcji, z której pobierzemy unikalne wartości.
Pole, na bazie którego wyszukane zostaną unikalne wartości.
Pole opcjonalne. Zapytanie określa, z których dokumentów kolekcji
będą otrzymywane unikalne wartości.
Polecenie:
znajduje unikalne wartości w ramach jednej kolekcji,
zwraca dokument zawierający tablicę unikalnych wartości,
zwracany dokument zawiera również wbudowany dokument ze
statystykami wykonania i planem zapytania.
MongoDB - grupowanie
49/52
Polecenie distinct() - przykłady
db.runCommand({distinct:"osoby"}) // bez argumentu key - pusta tablica i ...
{
"values" : [ ],
"stats" : {
"n" : 50,
"nscanned" : 50,
"nscannedObjects" : 50,
"timems" : 0,
"cursor" : "BasicCursor"
}, "ok" : 1
}
db.runCommand({distinct:"osoby", key:"zatrudniony"})
{
"values" : [ true, false ],
"stats" : {
"n" : 50,
"nscanned" : 50,
"nscannedObjects" : 50,
"timems" : 0,
"cursor" : "BasicCursor"
}, "ok" : 1
}
MongoDB - grupowanie
50/52
Polecenie distinct() - przykłady
db.runCommand({distinct:"osoby", key:"oczy", query:{oczy:{$regex:/ie/i}}})
{
"values" : [ "niebieskie", "zielone" ],
"stats" : {
"n" : 28,
"nscanned" : 50,
"nscannedObjects" : 50,
"timems" : 0,
"cursor" : "BasicCursor"
}, "ok" : 1
}
db.runCommand({distinct:"resteuracje", key:"adres.ulica"})
{
"values" : [ ..., "Nelson Ave", "W 13Th St", "W 15Th St", "E 48Th St" ],
"stats" : {
"n" : 25359,
"nscanned" : 25359,
"nscannedObjects" : 25359,
"timems" : 104,
"cursor" : "BasicCursor"
}, "ok" : 1
}
MongoDB - grupowanie
51/52
Źródła
W wykładzie wykorzystano materiały:
https://docs.mongodb.org/manual/aggregation/
https://docs.mongodb.org/manual/reference/command/
MongoDB - grupowanie
52/52