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