2010-11-28 28 views
3

J'essaie d'obtenir une liste de valeurs uniques du champ 'type' de ma collection mongodb. Exemples de documents ci-dessous:mongodb php obtenant des champs valeurs uniques

{ 
     "_id" : ..., 
     "type" : "report", 
     "tasks" : ... 
} 
{ 
     "_id" : ..., 
     "type" : "research", 
     "tasks" : ... 
} 
{ 
     "_id" : ..., 
     "type" : "memo", 
     "tasks" : ... 
} 
{ 
     "_id" : ..., 
     "type" : "memo", 
     "tasks" : ... 
} 
{ 
     "_id" : ..., 
     "type" : "report", 
     "tasks" : ... 
} 
{ 
     "_id" : ..., 
     "type" : "report", 
     "tasks" : ... 
} 

Je suis à la recherche, classés par ordre de fréquence, les types uniques qui sont dans le domaine du type des documents, donc:

["report", "memo", "research"] 

Quelle est la meilleure façon de le faire ? Espérons que je peux le faire en questionnant avec mongo et non le téléchargement de la collection ...

Répondre

11

Sur une norme SQL SGBD ce sera fait avec la requête suivante:

SELECT type, count(*) as ct FROM table GROUP BY type ORDER BY ct; 

sur MongoDB ce serait fait en utilisant la fonction de groupe, même si elle est un peu plus compliqué:

db.collection.group(
      {key: { "type":true}, 
      reduce: function(obj,prev) { prev.count += 1; }, 
      initial: { count: 0 } 
      }); 

ici Je demande à la base de données de renvoyer des valeurs pour la clé "type" (d'où le "vrai"), et pour chaque valeur, la fonction de réduction donnée sera utilisée pour agréger les enregistrements trouvés. Ici, je ne fais que mettre à jour le nombre de fois que chaque enregistrement apparaît. Si vous exécutez cette requête, vous obtiendrez quelque chose comme ceci:

[ 
    { 
     "type" : "report", 
     "count" : 5 
    }, 
    { 
     "type" : "memo", 
     "count" : 15 
    } 
    { 
     "type" : "research", 
     "count" : 3 
    } 

] 

Vous remarquerez que ceci n'est pas commandé; même les docteurs de mongodb disent que la manière la plus facile de la commander est de le faire côté client.

La documentation pertinente est here.

+0

Cette réponse devrait fonctionner. Juste quelques notes supplémentaires. Ce sera une requête lente sauf si 'type' est indexé. Même avec un index, vous allez essentiellement devoir «marcher» sur l'ensemble de l'indice. S'il s'agit d'une requête urgente, elle doit être configurée en tant que map-reduce et s'exécuter selon un planning. –

+0

Gates VP a entièrement raison, soyez conscient des problèmes de performance. Une solution possible consiste à conserver un cache des comptes pour chaque valeur possible de «type» (en supposant que vous les avez dans une autre collection) et mettre à jour ce compteur chaque fois qu'un enregistrement est ajouté ou supprimé. Signifie un faible impact sur les performances lors de l'ajout/la suppression d'enregistrements, mais si vous avez besoin d'un accès fréquent à vos types et à vos comptes, vous gagnerez du temps à long terme. – Roadmaster

+0

Oublié de dire merci, merci, c'est exactement ce que je voulais. +1 – Mark

1

Vous pouvez utiliser distincts: http://www.mongodb.org/display/DOCS/Aggregation#Aggregation-Distinct

Il y a un exemple dans le php doc: http://php.net/manual/en/mongodb.command.php

$types = $db->command(array("distinct" => "yourCollection", "key" => "type")); 

foreach ($types['values'] as $type) { 
    echo "$type\n"; 
} 

I Je ne sais pas si les résultats sont classés par fréquence.

+0

Aurait toujours besoin d'un moyen d'obtenir les fréquences pour chaque valeur unique afin de les trier par fréquence. Je n'ai trouvé aucun moyen de le faire en utilisant distinct, d'où la solution légèrement plus impliquée avec le groupe. – Roadmaster