ShotGrid find pagination stability with limit and offset under concurrent changes
0 reputation · 26 May 2023, 20:31 UTC
0 reputation · 26 May 2023, 20:31 UTC
Goal is to define reliable bulk retrieval semantics for ShotGrid API find operations when result sets exceed a single page.
Documented capability uses limit and offset paging for find requests, with a maximum page size in the order of hundreds to a thousand entities. Pagination relies on offset rather than stable cursor tokens. Administrative settings and deployment type can affect effective limits for attachments and API handling.
Uncertainty remains about result consistency when entities are created or deleted between successive pages, and about the inclusion rules for soft-deleted entities across REST API, Python API and web UI. No uniform documented guarantee is available for ordering stability or visibility of deleted revisions in find versus direct read calls.
What ordering guarantees, if any, are documented for paginated find results for a given filter? Does ShotGrid define expected behavior for offset shifts caused by concurrent entity creation or deletion during a multi-page retrieval? Is there a documented pattern for deterministic bulk access that avoids duplicate or missing entities under concurrent modification?
30275 reputation · 27 May 2023, 05:31 UTC
ShotGrid does not provide a native cursor-based pagination mechanism for find operations. Because it relies on limit and offset, there are no documented guarantees for result stability under concurrent modifications. If entities are created or deleted between successive page requests, the result set will "drift," leading to duplicate or missing records.
Since offset is a numerical skip count rather than a pointer to a specific record, the following behaviors occur during multi-page retrieval:
To minimize inconsistency, you must implement a deterministic sort order and a sliding window approach. While this does not eliminate drift, it makes the behavior predictable.
order parameter (typically id). Without a unique sort key, the database may return records in an inconsistent order across requests.offset, use the value of the last retrieved unique ID to filter the next page.# Example logic for stable retrieval
last_id = 0
while True:
# Filter for IDs greater than the last seen ID
filters = [ ['id', 'gt', last_id], ... ]
results = sg.find(entity='Asset', filters=filters, order=[['id', 'asc']], limit=100)
if not results:
break
# Process results and update the pointer
last_id = results[-1]['id']
To verify the stability of your current implementation, perform these tests in a sandbox environment:
Diagnostic Detail Needed: Are you utilizing the Python API wrapper or raw REST calls? The Python API handles some request batching differently, which may impact how you implement the ID-based filtering loop.
Use comments to ask for clarification. Post a solution as an answer.
30,275 reputation · 27 May 2023, 03:49 UTC
When using keyset pagination you must match the filter operator to the sort direction: for order: [id_asc] filter with [['id', 'gt', last_id]]; for order: [id_desc] filter with [['id', 'lt', last_id]]. ShotGrid also enforces a hard limit of 500 entities per find request; any higher limit value is truncated to this maximum and may return a 400 error if the limit exceeds the allowed threshold.
# Ascending keyset example
last_id = 0
while True:
filters = [['id', 'gt', last_id]]
page = sg.find('Asset', filters=filters, order=[('id', 'asc')], limit=100)
if not page:
break
for entity in page:
process(entity)
last_id = entity['id']
# Descending keyset example
last_id = None # start with no upper bound
while True:
if last_id is None:
filters = [] # no filter for first page
else:
filters = [['id', 'lt', last_id]]
page = sg.find('Asset', filters=filters, order=[('id', 'desc')], limit=100)
if not page:
break
for entity in page:
process(entity)
last_id = entity['id']