使用页面大小和页码在 Cosmos DB 中分页

Pagination in Cosmos DB using Page Size and Page Number

我正在尝试使用 PageSizePageNumber 从 cosmosDB 中 return 项目。我知道我们可以在 MaxItemCount 中设置页面大小,但是我们如何在这个函数中放置页码?

这是我目前得到的结果:

  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;
        }

目前,分页支持仅基于延续标记

在下面找到关于此限制的一些有趣的讨论和功能请求:


--- 延续标记示例 ---

以下示例说明了一种方法(与您的方法非常相似),该方法根据所需的页码、页面大小和继续标记查询文档:

    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);
    }

现在,以下示例说明如何通过调用前面的方法检索给定页面的文档:

    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 ---");
    }

public 静态列表分页(int pageNo=1,int pageSize=20) { 列出 ArticlesList = new List(); var collection = UriFactory.CreateDocumentCollectionUri(databaseName, loginCollectionId);

    using (client = new DocumentClient(new Uri(endpointUrl), primaryKey))
    {

        var optionss = new FeedOptions
        {
            MaxItemCount = (pageNo!=1)?((pageNo-1)*pageSize): ((pageNo) * pageSize)
        };

        var query1 = client.CreateDocumentQuery<ArticlesListDetails>(collection, optionss).OrderByDescending(x => x._ts).AsDocumentQuery();

        var res = query1.ExecuteNextAsync<ArticlesListDetails>().Result;
        if (pageNo == 1)
        {
            return   ArticlesList = res.ToList();
        }
        else
        {
            var options = new FeedOptions
            {
                MaxItemCount = pageSize,
                RequestContinuation = res.ResponseContinuation
            };

            var query = client.CreateDocumentQuery<ArticlesListDetails>(collection, options).OrderByDescending(x => x._ts).AsDocumentQuery();

            while (query.HasMoreResults)
            {
                return  ArticlesList = query.ExecuteNextAsync<ArticlesListDetails>().Result.ToList();
            }
        }

        return ArticlesList;
    }

}

Skip & take 现在可以通过新的 OFFSET LIMIT 子句在 Cosmos DB 中使用: https://docs.microsoft.com/en-us/azure/cosmos-db/sql-query-offset-limit

有解决方法,但不是最优方法:

...
int pageNumber = 1;
int pageSize = 10;
...
    var query = Client.CreateDocumentQuery<T>(
                    UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId),
                    new FeedOptions { MaxItemCount = pageNumber * pageSize }) // Limit count or returned items
                    .Where(predicate)
                    .AsDocumentQuery();

                var results = new List<T>();
                int resultsToSkip = (pageNumber - 1) * pageSize;

                while (query.HasMoreResults)
                {
                    var result = await query.ExecuteNextAsync<T>();

                    // Skip pages, not optimal way, the best solution is to use RequestContinuation token.
                    if (resultsToSkip > 0)
                    {
                        resultsToSkip--;
                        continue;
                    }

                    results.AddRange(result);
                }

                return results;
    ...