web-dev-qa-db-fra.com

Comment vérifier si un curseur pymongo a des résultats de requête

Je dois vérifier si une instruction find renvoie une requête non vide.

Ce que je faisais était le suivant:

query = collection.find({"string": field})
if not query: #do something

Ensuite, j'ai réalisé que mon instruction if n'a jamais été exécutée car find renvoie un curseur, que la requête soit vide ou non.

J'ai donc vérifié le documentation et je trouve deux méthodes qui peuvent m'aider:

  1. count(with_limit_and_skip=False) qui (d'après la description):

    Renvoie le nombre de documents dans l'ensemble de résultats pour cette requête.

    Cela semble être un bon moyen de vérifier, mais cela signifie que je dois compter tous les résultats dans le curseur pour savoir s'il est nul ou non, non? Un peu cher?

  2. retrieved qui (d'après la description):

    Le nombre de documents récupérés jusqu'à présent.

    Je l'ai testé sur un ensemble de requêtes vide et il renvoie zéro, mais ce n'est pas clair et je ne sais pas si cela me convient.

Alors, quelle est la meilleure façon (meilleure pratique) de vérifier si une requête find() renvoie un ensemble vide ou non? L'une des méthodes décrites ci-dessus convient-elle à cette fin? Et la performance? Y a-t-il d'autres façons de procéder?


Juste pour être clair: j'ai besoin de savoir si la requête est vide et j'aimerais trouver le meilleur moyen avec le curseur en ce qui concerne les performances et être Pythonic.

29
boh717

[~ # ~] modifier [~ # ~] : Bien que cela soit vrai en 2014, les versions modernes de pymongo et MongoDB ont changé cela comportement. Attention à l'acheteur:

.count() est la bonne façon de trouver le nombre de résultats renvoyés dans la requête. La méthode count() n'épuise pas l'itérateur pour votre curseur, vous pouvez donc effectuer une vérification .count() en toute sécurité avant d'itérer sur les éléments du jeu de résultats.

Les performances de la méthode de comptage ont été considérablement améliorées dans MongoDB 2.4. La seule chose qui pourrait ralentir votre count est de savoir si la requête a un index défini ou non. Pour savoir si vous avez un index 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 index sur votre champ string pour cette requête.


[~ # ~] modifier [~ # ~] : comme l'a souligné @alvapan, pymongo a déconseillé cette méthode dans pymongo 3.7 + et préfère maintenant que vous utilisiez 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és sur une requête est de vérifier le .retreived compteur sur la requête après avoir effectué une itération dessus, ou enumeratela 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 manière:

# 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))
35
VooDooNOFX

Que diriez-vous d'utiliser simplement 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ée, vous pouvez passer fields = {"string":1, "_id" :0}, ce qui en fait une requête indexée, ce qui est encore plus rapide.

7
Baruch Oxman

Une autre solution consiste à convertir le curseur en liste, si le curseur n'a pas de données, alors la liste vide sinon la liste contient toutes les données.

 doc_list = collection.find({}); #find all data
 have_list = True if len(list(doc_list)) else False;
6
Biplab Malakar

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

(Utilisation de MongoDB 2.6.7, 2015-03-26)

3
Arnaud Fouchet