web-dev-qa-db-fra.com

pymongo.errors.CursorNotFound: l'ID de curseur '...' n'est pas valide sur le serveur

J'essaie de récupérer certains identifiants qui existent dans une base de données mongo avec le code suivant:

client = MongoClient('xx.xx.xx.xx', xxx)
db = client.test_database
db = client['...']
collection = db.test_collection
collection = db["..."]


for cursor in collection.find({ "$and" : [{ "followers" : { "$gt" : 2000 } }, { "followers" : { "$lt" : 3000 } }, { "list_followers" : { "$exists" : False } }] }): 
    print cursor['screenname']
    print cursor['_id']['uid']
    id = cursor['_id']['uid']

Cependant, après un court instant, je reçois cette erreur:

pymongo.errors.CursorNotFound: l'ID de curseur '...' n'est pas valide sur le serveur.

J'ai trouvé ceci article qui fait référence à ce problème. Néanmoins, je ne sais pas quelle solution adopter. Est-il possible d'utiliser find().batch_size(30)? Que fait exactement la commande ci-dessus? Puis-je prendre tous les identifiants de base de données en utilisant batch_size?

48
snake plissken

Vous obtenez cette erreur car le curseur expire sur le serveur (après 10 minutes d'inactivité).

De la documentation pymongo:

Les curseurs dans MongoDB peuvent expirer sur le serveur s'ils sont ouverts depuis longtemps sans qu'aucune opération ne soit effectuée sur eux. Cela peut entraîner le déclenchement d'une exception CursorNotFound lors d'une tentative d'itération du curseur.

Lorsque vous appelez la méthode collection.find, Elle interroge une collection et renvoie un curseur aux documents. Pour obtenir les documents, vous parcourez le curseur. Lorsque vous parcourez le curseur, le pilote envoie en fait des requêtes au serveur MongoDB pour extraire plus de données du serveur. La quantité de données renvoyées dans chaque demande est définie par la méthode batch_size().

De la documentation :

Limite le nombre de documents retournés dans un lot. Chaque lot nécessite un aller-retour vers le serveur. Il peut être ajusté pour optimiser les performances et limiter le transfert de données.

La définition de batch_size à une valeur inférieure vous aidera à résoudre les erreurs d'erreurs de délai, mais cela augmentera le nombre de fois où vous allez accéder au serveur MongoDB pour obtenir tous les documents.

La taille de lot par défaut:

Pour la plupart des requêtes, le premier lot renvoie 101 documents ou juste assez de documents pour dépasser 1 mégaoctet. La taille du lot ne dépassera pas la taille maximale du document BSON (16 Mo).

Il n'y a pas de "bonne" taille de lot universelle. Vous devez tester avec différentes valeurs et voir quelle est la valeur appropriée pour votre cas d'utilisation, c'est-à-dire combien de documents pouvez-vous traiter dans une fenêtre de 10 minutes.

Le dernier recours sera que vous définissiez no_cursor_timeout=True. Mais vous devez vous assurer que le curseur est fermé une fois le traitement des données terminé.

Exemple:

cursor = collection.find({"x": 1}, no_cursor_timeout=True)
for doc in cursor:
    # do something with doc
cursor.close()
73
Christian P

Utilisation no_cursor_timeout=True comme ça:

cursor=db.images.find({}, {'id':1, 'image_path':1, '_id':0}, no_cursor_timeout=True)
for i in cursor:
    # .....
    # .....
cursor.close() # use this or cursor keeps waiting so ur resources are used up
45
Mani

Vous utilisiez le curseur plus que le temps mort (environ 10 minutes) de sorte que le curseur n'existe plus.

vous devez choisir une valeur faible de batch_size pour résoudre le problème:

(avec Pymongo par exemple)

col.find({}).batch_size(10)

ou

définissez le délai sur false col.find(timeout=False) et n'oubliez pas de fermer le curseur à la fin.

4
HISI