mongodb count nombre de valeurs distinctes par champ / clé

104

Existe-t-il une requête pour calculer le nombre de valeurs distinctes qu'un champ contient dans DB.

fe j'ai un champ pour le pays et il y a 8 types de valeurs de pays (espagne, angleterre, france, etc ...)

Si quelqu'un ajoute plus de documents avec un nouveau pays, j'aimerais que la requête renvoie 9.

Y a-t-il un moyen plus simple de regrouper et de compter?

Liatz
la source
2
Avez-vous examiné le cadre d' agrégation ?
WiredPrairie
1
Ou réduire la carte ?
WiredPrairie

Réponses:

198

MongoDB a une distinctcommande qui renvoie un tableau de valeurs distinctes pour un champ; vous pouvez vérifier la longueur du tableau pour un décompte.

Il existe également un db.collection.distinct()assistant shell :

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

> db.countries.distinct('country').length
4
Stennie
la source
47
cela ne fonctionne pas vraiment si votre nombre de valeurs distinctes est trop élevé ... si vous regardez des noms distincts de personnes dans le monde ou quelque chose comme ça. avez-vous une réponse qui évolue?
underrun
3
1+ pour la longueur. J'avais du mal à trouver quelque chose comme ça. Merci.
Adeel Ahmad
Je ne sais pas pourquoi ils n'utilisent pas count () là aussi
Marian Klühspies
1
@ MarianKlühspies - parce que c'est juste un tableau javascript, qui utilise la propriété length pour compter le nombre d'éléments.
UpTheCreek
Juste ce que je cherchais ... TY
Maulzey
113

Voici un exemple d'utilisation de l'API d'agrégation. Pour compliquer le cas, nous regroupons par mots insensibles à la casse de la propriété array du document.

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 }
]);

qui donnent un résultat tel que

{ "_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 }
expert
la source
2
Connecté juste pour + cette réponse. Merci! btw si vous le faites sur un champ unique, supprimez simplement la ligne de déroulement.
Richie Rich
@RichieRich, unwindest nécessaire car le code regroupe les valeurs individuelles d'un champ de tableau qui correspond à son distinctfonctionnement.
Paul
@Paul ce que Richie a dit, c'est que si le regroupement est effectué uniquement sur un champ "normal" (chaîne, int, etc.), vous n'avez pas besoin de l'étape de déroulement. N'est-ce pas correct?
guyarad
@guyarad unwindest nécessaire lorsque vous travaillez avec des tableaux.
Paul
+1 pour la réponse, exactement ce sur quoi je travaillais, même si distinct a ses propres charmes, mais ce n'est que de l'or :) - de toute façon, je dois en savoir plus sur les agrégats pour obtenir l'ensemble de résultats souhaité pour filtrer les données
Talha
21

Avec MongoDb 3.4.4 et les versions ultérieures, vous pouvez tirer parti de l'utilisation d'un $arrayToObjectopérateur et d'un $replaceRootpipeline pour obtenir les décomptes.

Par exemple, supposons que vous ayez une collection d'utilisateurs avec différents rôles et que vous souhaitiez calculer les nombres distincts des rôles. Vous devrez exécuter le pipeline agrégé suivant:

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

Exemple de sortie

{
    "user" : 67,
    "superuser" : 5,
    "admin" : 4,
    "moderator" : 12
}
Chridam
la source
Ce n'est pas la réponse à la question, mais cela est néanmoins utile. Je me demande comment cela fonctionne par rapport à .distinct().
Redsandro
9

Vous pouvez tirer parti des extensions Mongo Shell . Il s'agit d'une importation .js unique que vous pouvez ajouter à votre $HOME/.mongorc.js, ou par programme, si vous codez également dans Node.js / io.js.

Échantillon

Pour chaque valeur distincte du champ compte les occurrences dans les documents éventuellement filtrés par requête

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

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

Le paramètre de champ peut être un tableau de champs

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

{
  "Austin,Educator" : 1,
  "Aurelia,Educator" : 1,
  "Augustine,Carpenter" : 1,
  ...
}
Evandrix
la source
comment importer ceci dans le nœud?
Salmaan P
require("./script.js"), je suppose
evandrix
à droite, mais je n'ai pas pu obtenir les fonctions à l'intérieur. Comment les utiliser. Ils sont définis comme db.protoptype.distinctAndCount
Salmaan P
Il y a une section pratique dans le readme du dépôt (RTFM! 1 !! 1!) En gros, placez le .mongorc.jsfichier dans votre répertoire personnel. Terminé.
Janis F
6

Pour trouver distinct dans la field_1collection, mais nous voulons aussi une WHEREcondition que nous pouvons faire comme suit:

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

Alors, trouvez un numéro distinct namesd'une collection où l'âge> 25 sera comme:

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

J'espère que ça aide!

Vimal
la source