使用页面大小和页码在 Cosmos DB 中分页
Pagination in Cosmos DB using Page Size and Page Number
我正在尝试使用 PageSize
和 PageNumber
从 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;
}
目前,分页支持仅基于延续标记。
在下面找到关于此限制的一些有趣的讨论和功能请求:
- 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
--- 延续标记示例 ---
以下示例说明了一种方法(与您的方法非常相似),该方法根据所需的页码、页面大小和继续标记查询文档:
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;
...
我正在尝试使用 PageSize
和 PageNumber
从 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;
}
目前,分页支持仅基于延续标记。
在下面找到关于此限制的一些有趣的讨论和功能请求:
- 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
--- 延续标记示例 ---
以下示例说明了一种方法(与您的方法非常相似),该方法根据所需的页码、页面大小和继续标记查询文档:
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;
...