Restez organisé à l'aide des collections
Enregistrez et classez les contenus selon vos préférences.
Les curseurs de requêtes permettent à une application de récupérer les résultats d'une requête sous forme de lots pratiques. Il est recommandé de privilégier leur utilisation à celle de décalages d'entiers pour la pagination.
Pour savoir comment structurer des requêtes pour l'application, consultez la page Requêtes.
Curseurs de requêtes
Les curseurs de requêtes permettent à une application de récupérer les résultats d'une requête sous forme de lots pratiques sans entraîner la surcharge d'un décalage de requête. Après avoir effectué une opération de récupération, l'application peut obtenir un curseur, qui est une chaîne opaque encodée en base64 indiquant la position d'index du dernier résultat récupéré. L'application peut enregistrer cette chaîne, par exemple dans Datastore, dans Memcache, dans une charge utile de tâche de la file d'attente de tâches, ou en l'intégrant dans une page Web en tant que paramètre HTTP GET ou POST. Elle peut ensuite utiliser le curseur comme point de départ d'une opération de récupération ultérieure, afin d'obtenir le prochain lot de résultats à partir du point où la récupération précédente s'est terminée. Une récupération peut également spécifier un curseur de fin afin de limiter l'étendue de l'ensemble de résultats renvoyé.
Décalages et curseurs
Bien que Datastore accepte les décalages d'entiers, vous devriez éviter de les utiliser. Employez plutôt des curseurs. L'utilisation d'un décalage permet uniquement d'éviter de renvoyer les entités ignorées à l'application, mais ces dernières sont tout de même récupérées en interne. Les entités ignorées ont une incidence sur la latence de la requête, et l'application est facturée pour les opérations de lecture nécessaires à leur récupération. En faisant appel à des curseurs plutôt qu'à des décalages, vous évitez tous ces coûts.
Exemple de curseur de requête
Dans Python, une application obtient un curseur après avoir récupéré les résultats de la requête en appelant la méthode cursor() de l'objet Query. Pour récupérer des résultats supplémentaires à partir du point du curseur, l'application prépare une requête similaire avec le même genre d'entité, les mêmes filtres et les mêmes ordres de tri, puis transmet le curseur à la méthode with_cursor() de la requête avant de procéder à la récupération :
fromgoogle.appengine.apiimportmemcachefromgoogle.appengine.extimportdb# class Person(db.Model): ...# Start a query for all Person entitiespeople=Person.all()# If the application stored a cursor during a previous request, use itperson_cursor=memcache.get('person_cursor')ifperson_cursor:people.with_cursor(start_cursor=person_cursor)# Iterate over the resultsforpersoninpeople:# Do something# Get updated cursor and store it for next timeperson_cursor=people.cursor()memcache.set('person_cursor',person_cursor)
Limites relatives aux curseurs
Les curseurs sont soumis aux limites suivantes :
Un curseur ne peut être utilisé que par l'application qui a exécuté la requête d'origine et uniquement pour poursuivre la même requête. Pour utiliser le curseur dans une opération de récupération ultérieure, vous devez reconstituer exactement la requête d'origine, avec le même genre d'entité, le même filtre d'ancêtre, les mêmes filtres de propriétés et les mêmes ordres de tri. Il est impossible de récupérer des résultats à l'aide d'un curseur sans configurer une requête identique à celle à partir de laquelle il a été généré.
Étant donné que les opérateurs != et IN sont mis en œuvre avec plusieurs requêtes, les requêtes qui les utilisent ne sont pas compatibles avec les curseurs.
Les curseurs ne fonctionnent pas toujours comme prévu avec une requête utilisant un filtre d'inégalité ou un ordre de tri sur une propriété comportant plusieurs valeurs. Comme la logique de déduplication de ces propriétés à valeurs multiples ne persiste pas entre les récupérations, le même résultat peut être renvoyé plusieurs fois.
Les nouvelles versions d'App Engine peuvent modifier des détails de mise en œuvre interne, et ainsi invalider les curseurs qui en dépendent. Si une application tente d'employer un curseur qui n'est plus valide, Datastore déclenche une exception BadRequestError.
Mises à jour des curseurs et des données
La position du curseur se définit comme l'emplacement dans la liste de résultats après renvoi du dernier résultat. Un curseur n'est pas une position relative dans la liste (ce n'est pas un décalage). Il s'agit d'un marqueur auquel Datastore peut accéder lors du lancement d'une analyse des résultats dans un index. Si les résultats d'une requête changent entre les différentes utilisations d'un curseur, la requête remarque uniquement les modifications apportées aux résultats situés après le curseur. Si un nouveau résultat apparaît avant la position du curseur pour cette requête, il n'est pas renvoyé lors de la récupération des résultats situés après le curseur.
De la même façon, si une entité ne constitue plus un résultat d'une requête, alors qu'elle apparaissait avant le curseur, les résultats situés après le curseur ne changent pas. Si le dernier résultat renvoyé est supprimé de l'ensemble de résultats, le curseur est toujours capable de localiser le résultat suivant.
Lors de la récupération des résultats de la requête, vous pouvez utiliser un curseur de début et un curseur de fin pour renvoyer un groupe continu de résultats à partir de Datastore. Lorsque vous utilisez un curseur de début et de fin pour récupérer les résultats, il n'est pas certain que vous obteniez la même taille de résultats que celle obtenue lorsque vous avez généré les curseurs.
Des entités peuvent être ajoutées ou supprimées de Datastore entre le moment où les curseurs sont générés et celui où ils sont employés dans une requête.
Sauf indication contraire, le contenu de cette page est régi par une licence Creative Commons Attribution 4.0, et les échantillons de code sont régis par une licence Apache 2.0. Pour en savoir plus, consultez les Règles du site Google Developers. Java est une marque déposée d'Oracle et/ou de ses sociétés affiliées.
Dernière mise à jour le 2025/09/04 (UTC).
[[["Facile à comprendre","easyToUnderstand","thumb-up"],["J'ai pu résoudre mon problème","solvedMyProblem","thumb-up"],["Autre","otherUp","thumb-up"]],[["Difficile à comprendre","hardToUnderstand","thumb-down"],["Informations ou exemple de code incorrects","incorrectInformationOrSampleCode","thumb-down"],["Il n'y a pas l'information/les exemples dont j'ai besoin","missingTheInformationSamplesINeed","thumb-down"],["Problème de traduction","translationIssue","thumb-down"],["Autre","otherDown","thumb-down"]],["Dernière mise à jour le 2025/09/04 (UTC)."],[[["\u003cp\u003eQuery cursors allow applications to retrieve query results in batches, marking the position of the last retrieved result as an opaque, base64-encoded string.\u003c/p\u003e\n"],["\u003cp\u003eUsing cursors instead of integer offsets is recommended because offsets still retrieve skipped entities internally, affecting latency and incurring read operation costs.\u003c/p\u003e\n"],["\u003cp\u003eCursors can be saved and used later to continue a query from where it left off, allowing applications to get the next batch of results.\u003c/p\u003e\n"],["\u003cp\u003eCursors have limitations, such as only being usable by the same application for the same query and not supporting \u003ccode\u003e!=\u003c/code\u003e and \u003ccode\u003eIN\u003c/code\u003e operators.\u003c/p\u003e\n"],["\u003cp\u003eThe position of a cursor is defined as the location after the last returned result, and while it is not affected by results that come before the cursor, new additions or removals after the cursor can impact results.\u003c/p\u003e\n"]]],[],null,["# Query Cursors\n\n*Query cursors* allow an application to retrieve a query's results in convenient\nbatches, and are recommended over using integer offsets for pagination.\nSee [Queries](/appengine/docs/legacy/standard/python/datastore/queries) for more information on structuring queries for your app.\n\nQuery cursors\n-------------\n\n*Query cursors* allow an application to retrieve a query's results in convenient\nbatches without incurring the overhead of a query offset. After performing a\n[retrieval operation](/appengine/docs/legacy/standard/python/datastore/retrieving-query-results), the application can obtain a\ncursor, which is an opaque base64-encoded string marking the index position of\nthe last result retrieved. The application can save this string, for example in\nDatastore, in Memcache, in a Task Queue task payload, or embedded in\na web page as an HTTP `GET` or `POST` parameter, and can then use the cursor as\nthe starting point for a subsequent retrieval operation to obtain the next batch\nof results from the point where the previous retrieval ended. A retrieval can\nalso specify an end cursor, to limit the extent of the result set returned.\n\nOffsets versus cursors\n----------------------\n\nAlthough Datastore supports integer offsets, you should avoid\nusing them. Instead, use cursors. Using an offset only avoids returning the\nskipped entities to your application, but these entities are still retrieved\ninternally. The skipped entities do affect the latency of the query, and your\napplication is billed for the read operations required to retrieve them. Using\ncursors instead of offsets lets you avoid all these costs.\n\nQuery cursor example\n--------------------\n\nIn Python, an application obtains a cursor after retrieving query results by\ncalling the `Query` object's [`cursor()`](/appengine/docs/legacy/standard/python/datastore/queryclass#Query_cursor) method. To\nretrieve additional results from the point of the cursor, the application\nprepares a similar query with the same entity kind, filters, and sort orders,\nand passes the cursor to the query's\n[`with_cursor()`](/appengine/docs/legacy/standard/python/datastore/queryclass#Query_with_cursor) method before performing the\nretrieval: \n\n from google.appengine.api import memcache\n from google.appengine.ext import db\n\n # class Person(db.Model): ...\n \n # Start a query for all Person entities\n people = Person.all()\n \n # If the application stored a cursor during a previous request, use it\n person_cursor = memcache.get('person_cursor')\n if person_cursor:\n people.with_cursor(start_cursor=person_cursor)\n \n # Iterate over the results\n for person in people:\n # Do something\n \n # Get updated cursor and store it for next time\n person_cursor = people.cursor()\n memcache.set('person_cursor', person_cursor)\n\n| **Note:** Because of the way the iterator interface retrieves results in batches, getting a cursor may result in an additional call to Datastore to position the cursor where the iterator left off. If using only a start cursor, and if you know how many results you need ahead of time, it's faster to use [`fetch()`](/appengine/docs/legacy/standard/python/datastore/queryclass#Query_fetch).\n| **Caution:** Be careful when passing a Datastore cursor to a client, such as in a web form. Although the client cannot change the cursor value to access results outside of the original query, it is possible for it to decode the cursor to expose information about result entities, such as the application ID, entity kind, key name or numeric ID, ancestor keys, and properties used in the query's filters and sort orders. If you don't want users to have access to that information, you can encrypt the cursor, or store it and provide the user with an opaque key.\n\n### Limitations of cursors\n\nCursors are subject to the following limitations:\n\n- A cursor can be used only by the same application that performed the original query, and only to continue the same query. To use the cursor in a subsequent retrieval operation, you must reconstitute the original query exactly, including the same entity kind, ancestor filter, property filters, and sort orders. It is not possible to retrieve results using a cursor without setting up the same query from which it was originally generated.\n- Because the `!=` and `IN` operators are implemented with multiple queries, queries that use them do not support cursors.\n- Cursors don't always work as expected with a query that uses an inequality filter or a sort order on a property with multiple values. The de-duplication logic for such multiple-valued properties does not persist between retrievals, possibly causing the same result to be returned more than once.\n- New App Engine releases might change internal implementation details, invalidating cursors that depend on them. If an application attempts to use a cursor that is no longer valid, Datastore raises a [`BadRequestError`](/appengine/docs/legacy/standard/python/datastore/exceptions#BadRequestError) exception.\n\n### Cursors and data updates\n\nThe cursor's position is defined as the location in the result list after the\nlast result returned. A cursor is not a relative position in the list\n(it's not an offset); it's a marker to which Datastore can jump\nwhen starting an index scan for results. If the results for a query change\nbetween uses of a cursor, the query notices only changes that occur in results\nafter the cursor. If a new result appears before the cursor's position for the\nquery, it will not be returned when the results after the cursor are fetched.\nSimilarly, if an entity is no longer a result for a query but had appeared\nbefore the cursor, the results that appear after the cursor do not change. If\nthe last result returned is removed from the result set, the cursor still knows\nhow to locate the next result.\n\nWhen retrieving query results, you can use both a start cursor and an end cursor\nto return a continuous group of results from Datastore. When\nusing a start and end cursor to retrieve the results, you are not guaranteed\nthat the size of the results will be the same as when you generated the cursors.\nEntities may be added or deleted from Datastore between the\ntime the cursors are generated and when they are used in a query.\n\nWhat's next?\n------------\n\n- [Learn how to specify what a query returns and further control query\n results](/appengine/docs/legacy/standard/python/datastore/retrieving-query-results).\n- Learn the [common restrictions](/appengine/docs/legacy/standard/python/datastore/query-restrictions) for queries on Datastore.\n- [Understand data consistency](/appengine/docs/legacy/standard/python/datastore/data-consistency) and how data consistency works with different types of queries on Datastore.\n- Learn the [basic syntax and structure of queries](/appengine/docs/legacy/standard/python/datastore/queries) for Datastore."]]