2017-09-07 2 views
0

J'ai une collection:mongodb comment obtenir un document qui a une valeur maximale de chaque « groupe avec la même clé »

{'_id':'008','name':'ada','update':'1504501629','star':3.6,'desc':'ok', ...} 
{'_id':'007','name':'bob','update':'1504501614','star':4.2,'desc':'gb', ...} 
{'_id':'005','name':'ada','update':'1504501532','star':3.2,'desc':'ok', ...} 
{'_id':'003','name':'bob','update':'1504501431','star':4.5,'desc':'bg', ...} 
{'_id':'002','name':'ada','update':'1504501378','star':3.4,'desc':'no', ...} 
{'_id':'001','name':'ada','update':'1504501325','star':3.6,'desc':'ok', ...} 
{'_id':'000','name':'bob','update':'1504501268','star':4.3,'desc':'gg', ...} 
... 

si je veux que le résultat est, la valeur maximale de la « mise à jour » du même « nom », signifie le nouveau document « nom », obtenir le document entier:

{'_id':'008','name':'ada','update':'1504501629','star':3.6,'desc':'ok', ...} 
{'_id':'007','name':'bob','update':'1504501614','star':4.2,'desc':'gb', ...} 
... 

Comment le faire le plus efficace?

je le fais maintenant en python est:

result=[] 
for name in db.collection.distinct('name'): 
    result.append(db.collection.find({'name':name}).sort('update',-1)[0]) 

est il ne 'trouver' trop de fois?

=====

Je le fais pour les données d'exploration avec « nom », obtenir beaucoup d'autres clés, et chaque fois que j'insérer un document, je mis une clé nommée « mise à jour ». Lorsque j'utilise la base de données, je veux le plus récent document de 'nom' spécifique. donc ça ne peut pas simplement utiliser $ group. Comment dois-je faire? re concevoir la structure db ou mieux trouver?

=====

amélioré!
J'ai essayé de créer l'index de 'nom' & 'mise à jour', le processus est raccourci d'une demi-heure à 30 secondes!

Mais je me réjouis encore pour une meilleure solution^_^

Répondre

0

Votre scénario de cas d'utilisation convient vraiment bien pour l'agrégation. Comme je vois dans votre question, vous savez déjà, mais ne peut pas comprendre comment utiliser $group et prendre tout le document qui a la mise à jour maximale. Si vous $sort vos documents avant $group vous pouvez utiliser l'opérateur $first. Donc, pas besoin d'envoyer une requête de recherche pour chaque nom.

db.collection.aggregate(
{ $sort: { "name": 1, "update": -1 } }, 
{ $group: { _id: "$name", "update": { $first: "$update" }, "doc_id": { $first: "$_id" } } } 
) 

Je n'ai pas ajouté une opération $project supplémentaire pour agréger, vous pouvez simplement ajouter des champs que vous voulez en résultat $group avec l'opérateur $first.

De plus, si vous regardez de plus près de $sort opération, vous pouvez le voir utilise l'index nouvellement créé, de sorte que vous avez fait bon d'ajouter que, sinon je le recommande aussi :)

Mise à jour: Pour votre question dans le commentaire:

Vous devez écrire toutes les clés dans $group. Mais si vous pensez qu'il va mal paraître ou nouveaux fileds viendra à l'avenir et ne veut pas réécrire $group chaque fois, je le ferais:

d'abord obtenir tous _id champs de documents souhaités dans l'agrégation, puis obtenir ces documents une requête find avec l'opérateur $in.

db.collection.find({ "_id": { $in: [<ids returned in aggregation] } })

+0

merci pour votre réponse. J'ai essayé l'agrégation, mais si vous utilisez $ group, en tant que votre méthode, je peux obtenir 3 clés seulement.Mais je veux tout le document, pas seulement le '_id'. Hier, j'ai essayé d'une autre façon, utilisez l'agrégation $ trier toutes les données dans la collection, charger en python et supprimer les doublons. Le processus a été raccourci à 6 secondes. Mais maintenant, la collection a 120k + documents, et 26k 'nom' unique serait prendre à chaque fois. Si la collection devient plus grande, prendre des données de collection entières devrait être plus lent. –

+0

ou shold J'écris toutes les clés dans $ group? J'ai plus de 40 touches ... –

+0

Bien, j'ai essayé de lister toutes les clés dans le groupe $, il a utilisé 25 secondes, la même chose que ma vieille méthode. –