mongodb count liczba odrębnych wartości na pole / klucz

104

Czy istnieje zapytanie do obliczenia, ile różnych wartości zawiera pole w bazie danych?

fe mam pole dla kraju i jest 8 typów wartości kraju (Hiszpania, Anglia, Francja itd.)

Jeśli ktoś doda więcej dokumentów z nowym krajem to chciałbym, żeby zapytanie zwróciło 9.

Czy jest łatwiejszy sposób niż grupowanie i liczenie?

Liatz
źródło
2
Czy spojrzałeś na ramy agregacji ?
WiredPrairie
1
Lub redukcja mapy ?
WiredPrairie
Możliwy duplikat liczby selekcji MongoDB (odrębny x) w kolumnie indeksowanej - policz unikalne wyniki dla dużych zestawów danych . Umieściłem tam swoją odpowiedź.
ekspert

Odpowiedzi:

198

MongoDB zawiera distinctpolecenie, które zwraca tablicę odrębnych wartości dla pola; możesz sprawdzić długość tablicy pod kątem liczby.

Jest też db.collection.distinct()pomocnik powłoki :

> db.countries.distinct('country');
[ "Spain", "England", "France", "Australia" ]

> db.countries.distinct('country').length
4
Stennie
źródło
47
to naprawdę nie działa, jeśli liczba różnych wartości jest zbyt duża ... jeśli szukałeś różnych nazw osób na świecie lub coś w tym stylu. czy masz odpowiedź, która się skaluje?
poniżej
3
1+ za długość. starałem się znaleźć coś takiego. Dzięki.
Adeel Ahmad
Nie wiem, dlaczego nie używają tam również count ()
Marian Klühspies
1
@ MarianKlühspies - ponieważ jest to po prostu tablica javascript, która używa właściwości length do zliczania liczby elementów.
UpTheCreek
Właśnie tego szukałem ... TY
Maulzey
113

Oto przykład użycia interfejsu API agregacji. Aby skomplikować sprawę, grupujemy według słów niewrażliwych na wielkość liter z właściwości tablicy dokumentu.

db.articles.aggregate([
    {
        $match: {
            keywords: { $not: {$size: 0} }
        }
    },
    { $unwind: "$keywords" },
    {
        $group: {
            _id: {$toLower: '$keywords'},
            count: { $sum: 1 }
        }
    },
    {
        $match: {
            count: { $gte: 2 }
        }
    },
    { $sort : { count : -1} },
    { $limit : 100 }
]);

które dają wynik taki jak

{ "_id" : "inflammation", "count" : 765 }
{ "_id" : "obesity", "count" : 641 }
{ "_id" : "epidemiology", "count" : 617 }
{ "_id" : "cancer", "count" : 604 }
{ "_id" : "breast cancer", "count" : 596 }
{ "_id" : "apoptosis", "count" : 570 }
{ "_id" : "children", "count" : 487 }
{ "_id" : "depression", "count" : 474 }
{ "_id" : "hiv", "count" : 468 }
{ "_id" : "prognosis", "count" : 428 }
ekspert
źródło
2
Zalogowano się tylko po to, aby + tę odpowiedź. Dzięki! przy okazji, jeśli robisz to na unikalnym polu, po prostu usuń rozwijaną linię.
Richie Rich,
@RichieRich, unwindjest konieczne, ponieważ kod grupuje poszczególne wartości pola tablicy, które odpowiada temu, jak distinctdziała.
Paul,
@Paul Richie powiedział, że jeśli grupowanie jest wykonywane tylko w „zwykłym” polu (string, int itp.), Nie potrzebujesz kroku odwijania. Czy to nie jest poprawne?
guyarad
@guyarad unwindjest niezbędne podczas pracy z tablicami.
Paul
+1 za odpowiedź, dokładnie to, nad czym pracowałem, jakkolwiek odmienne ma swoje wdzięki ale to jest po prostu złoto :) - zresztą muszę poczytać więcej o agregatach, aby osiągnąć pożądany zestaw wyników do filtrowania danych
Talha
21

Dzięki MongoDb 3.4.4 i nowszym możesz wykorzystać $arrayToObjectoperatora i $replaceRootpotok, aby uzyskać liczby.

Na przykład załóżmy, że masz kolekcję użytkowników z różnymi rolami i chcesz obliczyć różne liczby ról. Musisz uruchomić następujący potok zagregowany:

db.users.aggregate([
    { "$group": {
        "_id": { "$toLower": "$role" },
        "count": { "$sum": 1 }
    } },
    { "$group": {
        "_id": null,
        "counts": {
            "$push": { "k": "$_id", "v": "$count" }
        }
    } },
    { "$replaceRoot": {
        "newRoot": { "$arrayToObject": "$counts" }
    } }    
])

Przykładowe dane wyjściowe

{
    "user" : 67,
    "superuser" : 5,
    "admin" : 4,
    "moderator" : 12
}
chridam
źródło
To nie jest odpowiedź na pytanie, ale mimo wszystko jest pomocna. Zastanawiam się, jak to działa w porównaniu z .distinct().
Redsandro
9

Możesz skorzystać z rozszerzeń powłoki Mongo . Jest to pojedynczy import .js, który możesz dołączyć do swojego $HOME/.mongorc.jslub programowo, jeśli kodujesz również w Node.js / io.js.

Próba

Dla każdej odrębnej wartości pola zlicza wystąpienia w dokumentach opcjonalnie filtrowane według zapytania

> db.users.distinctAndCount('name', {name: /^a/i})

{
  "Abagail": 1,
  "Abbey": 3,
  "Abbie": 1,
  ...
}

Parametr pola może być tablicą pól

> db.users.distinctAndCount(['name','job'], {name: /^a/i})

{
  "Austin,Educator" : 1,
  "Aurelia,Educator" : 1,
  "Augustine,Carpenter" : 1,
  ...
}
evandrix
źródło
jak zaimportować to w węźle?
Salmaan P
require("./script.js"), przypuszczam
evandrix
racja, ale nie udało mi się uzyskać funkcji w środku. Jak ich używać. Są zdefiniowane jako db.protoptype.distinctAndCount
Salmaan P
W pliku readme repozytorium znajduje się sekcja z instrukcjami (RTFM! 1 !! 1!). Zasadniczo umieść .mongorc.jsplik w katalogu domowym. Gotowe.
Janis F
6

Aby znaleźć field_1coś innego w kolekcji, ale chcemy też mieć jakiś WHEREwarunek, niż możemy zrobić, jak poniżej:

db.your_collection_name.distinct('field_1', {WHERE condition here and it should return a document})

Więc znajdź liczbę inną namesniż zbiór, w której wiek> 25 lat będzie wyglądał następująco:

db.your_collection_name.distinct('names', {'age': {"$gt": 25}})

Mam nadzieję, że to pomoże!

Vimal
źródło