Comment vérifier si un curseur pymongo a des résultats de requête
je dois vérifier si un find
l'instruction retourne une requête non vide.
ce que je faisais était le suivant:
query = collection.find({"string": field})
if not query: #do something
Puis j'ai réalisé que mon if
déclaration n'a jamais été exécuté parce que find
retourne un curseur, soit la requête est vide ou pas.
donc j'ai coché le documentation et j'ai trouver deux méthodes qui peuvent m'aider:
count(with_limit_and_skip=False)
qui (à partir de la description):Retourne le nombre de documents dans l'ensemble des résultats pour cette requête.
Il me semble un bon moyen de vérifier, mais cela signifie que j'ai besoin de compter tous les résultats de curseur pour savoir si c'est nul ou pas, non? Un peu cher?
retrieved
qui (à partir de la description):le nombre de documents récupérés à ce jour.
je l'ai testé sur une requête vide et il retourne zéro, mais c'est pas clairement ce qu'il fait et je ne sais pas si c'est bon pour moi.
Alors, quelle est la meilleure façon (best practice) pour vérifier si un find()
la requête renvoie un jeu vide ou non? Est l'une des méthodes décrites ci-dessus à droite à cette fin? Et que dire de la performance? Il existe d'autres moyens de le faire?
juste pour être clair: j'ai besoin de savoir si la requête est vide et je voudrais trouver le meilleur moyen avec le curseur en ce qui concerne la performance et être pythonic.
4 réponses
EDIT: alors que cela était vrai en 2014, les versions modernes de pymongo et MongoDB ont changé ce comportement. Acheteur prendre garde:
.count()
est la bonne façon de trouver le nombre de résultats retournés par la requête. count()
la méthode n'épuise pas l'itérateur pour votre curseur, vous pouvez donc faire un .count()
vérifier avant d'itérer les éléments dans le jeu de résultats.
la performance de la méthode de comptage a été amélioré en MongoDB 2.4. La seule chose qui pourrait ralentir votre count
si la requête a un indice fixés sur elle, ou pas. Pour savoir si vous avez un indice sur la requête, vous pouvez faire quelque chose comme
query = collection.find({"string": field})
print query.explain()
Si vous voyez BasicCursor
dans le résultat, vous avez besoin d'un indice sur votre string
champ pour cette requête.
EDIT: comme @alvapan l'a fait remarquer, pymongo a déprécié ceci méthode en pymongo 3.7 + et préfère maintenant que vous utilisez count_documents
dans une requête distincte.
item_count = collection.count_documents({"string": field})
La bonne façon de compter le nombre d'articles que vous avez retourné sur une requête est de vérifier l' .retreived
compteur sur la requête une fois que vous parcourez, ou enumerate
la requête en premier lieu:
# Using .retrieved
query = collection.find({"string": field})
for item in query:
print(item)
print('Located {0:,} item(s)'.format(query.retrieved))
Ou, d'une autre façon:
# Using the built-in enumerate
query = collection.find({"string": field})
for index, item in enumerate(query):
print(item)
print('Located {0:,} item(s)'.format(index+1))
pourquoi ne pas simplement utiliser find_one
au lieu de find
? Ensuite, vous pouvez simplement vérifier si vous avez obtenu un résultat ou None
. Et si "chaîne" est indexé, vous pouvez passer fields = {"string":1, "_id" :0}
, et ainsi en faire une requête index-only, ce qui est encore plus rapide.
une autre solution est de convertir le curseur en liste, si le curseur n'a pas de données alors la liste vide contient toutes les données.
doc_list = collection.find({}); #find all data
have_list = True if len(list(doc_list)) else False;
D'après mes tests, le moyen le plus rapide est
if query.first():
# do something
In [51]: %timeit query = MyMongoDoc.objects(); query.first()
100 loops, best of 3: 2.12 ms per loop
In [52]: %timeit query = MyMongoDoc.objects(); query.count()
100 loops, best of 3: 4.28 ms per loop
(En Utilisant MongoDB 2.6.7, 2015-03-26)