Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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;
        }
like image 243
superninja Avatar asked Jul 04 '18 00:07

superninja


People also ask

How do I find the size of my cosmos database?

Another way is to go under Containers Menu -> Browse. This view shows storage based on each container, cost, throughput. Also, it gives you the total of all of these.

How do you scale a Cosmos DB?

Sign in to the Azure portal or the Azure Cosmos DB explorer. Navigate to your Azure Cosmos DB account and open the Data Explorer tab. Select Scale and Settings for your container, or Scale for your database. Under Scale, select the Autoscale option and Save.

How does ETag work in cosmos?

If the ETag value matches the server ETag value, the resource is updated. If the ETag is no longer current, the server rejects the operation with an “HTTP 412 Precondition failure” response code. The client then re-fetches the resource to acquire the current ETag value for the resource.

What is Range index in Cosmos DB?

In Azure Cosmos DB, every container has an indexing policy that dictates how the container's items should be indexed. The default indexing policy for newly created containers indexes every property of every item and enforces range indexes for any string or number.


1 Answers

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

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

  • https://github.com/Azure/azure-documentdb-dotnet/issues/377
  • https://feedback.azure.com/forums/263030-azure-cosmos-db/suggestions/6350987--documentdb-allow-paging-skip-take

--- 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 ---");
    }
like image 61
Evandro de Paula Avatar answered Sep 21 '22 22:09

Evandro de Paula