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:
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?
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.
[~ # ~] 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 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 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))
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.
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;
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)