azureasp.net-corepaginationazure-cosmosdb

Pagination in Cosmos DB using Page Size and Page Number


I am trying to return items from cosmosDB using PageSize and PageNumber. I know we can set the page size in MaxItemCount, but how do we put the page number in this function?

Here's what I got so far:

  public async Task<IEnumerable<T>> RunSQLQueryAsync(string queryString, int pageSize, int pageNumber)
        {
            var feedOptions = new FeedOptions { MaxItemCount = pageSize, EnableCrossPartitionQuery = true };
            IQueryable<T> filter = _client.CreateDocumentQuery<T>(_collectionUri, queryString, feedOptions);
            IDocumentQuery<T> query = filter.AsDocumentQuery();
            var currentPageNumber = 0;
            var documentNumber = 0;
            List<T> results = new List<T>();
            while (query.HasMoreResults)
            {
                foreach (T t in await query.ExecuteNextAsync())
                {
                    results.Add(t);
                    documentNumber++;
                }
                currentPageNumber++;
                return results;

            }
            return null;
        }

Solution

  • Currently, the pagination support is based on continuation token only.

    Find below some interesting discussion and feature request about this limitation:


    --- Continuation Token Example ---

    The following example illustrates a method (very similar to yours) that queries documents based on the desired page number, page size and continuation token:

        private static async Task<KeyValuePair<string, IEnumerable<CeleryTask>>> QueryDocumentsByPage(int pageNumber, int pageSize, string continuationToken)
        {
            DocumentClient documentClient = new DocumentClient(new Uri("https://{CosmosDB/SQL Account Name}.documents.azure.com:443/"), "{CosmosDB/SQL Account Key}");
    
            var feedOptions = new FeedOptions {
                MaxItemCount = pageSize,
                EnableCrossPartitionQuery = true,
    
                // IMPORTANT: Set the continuation token (NULL for the first ever request/page)
                RequestContinuation = continuationToken 
            };
    
            IQueryable<CeleryTask> filter = documentClient.CreateDocumentQuery<CeleryTask>("dbs/{Database Name}/colls/{Collection Name}", feedOptions);
            IDocumentQuery<CeleryTask> query = filter.AsDocumentQuery();
    
            FeedResponse<CeleryTask> feedRespose = await query.ExecuteNextAsync<CeleryTask>();
    
            List<CeleryTask> documents = new List<CeleryTask>();
            foreach (CeleryTask t in feedRespose)
            {
                documents.Add(t);
            }
    
            // IMPORTANT: Ensure the continuation token is kept for the next requests
            return new KeyValuePair<string, IEnumerable<CeleryTask>>(feedRespose.ResponseContinuation, documents);
        }
    

    Now, the following example illustrates how to retrieve documents for a given page by calling the previous method:

        private static async Task QueryPageByPage()
        {
            // Number of documents per page
            const int PAGE_SIZE = 3;
    
            int currentPageNumber = 1;
            int documentNumber = 1;
    
            // Continuation token for subsequent queries (NULL for the very first request/page)
            string continuationToken = null;
    
            do
            {
                Console.WriteLine($"----- PAGE {currentPageNumber} -----");
    
                // Loads ALL documents for the current page
                KeyValuePair<string, IEnumerable<CeleryTask>> currentPage = await QueryDocumentsByPage(currentPageNumber, PAGE_SIZE, continuationToken);
    
                foreach (CeleryTask celeryTask in currentPage.Value)
                {
                    Console.WriteLine($"[{documentNumber}] {celeryTask.Id}");
                    documentNumber++;
                }
    
                // Ensure the continuation token is kept for the next page query execution
                continuationToken = currentPage.Key;
                currentPageNumber++;
            } while (continuationToken != null);
    
            Console.WriteLine("\n--- END: Finished Querying ALL Dcuments ---");
        }