使用页面大小和页面编号在Cosmos DB中进行分页

时间:2018-07-04 00:34:22

标签: azure asp.net-core pagination azure-cosmosdb paging

我正在尝试使用PageSizePageNumber从cosmosDB返回项目。我知道我们可以在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;
        }

4 个答案:

答案 0 :(得分:14)

当前,分页支持仅基于延续令牌

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


---延续令牌示例---

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

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

答案 1 :(得分:3)

现在可以通过新的OFFSET LIMIT子句在Cosmos DB中使用“跳过并获取”功能: https://docs.microsoft.com/en-us/azure/cosmos-db/how-to-sql-query#OffsetLimitClause

答案 2 :(得分:0)

公共静态列表分页(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;
    }

}

答案 3 :(得分:0)

有一种解决方法,但这不是最佳选择:

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