在 C# 中针对没有 Skip 的 DocumentDB 进行分页

Pagination in C# against DocumentDB without Skip

我想知道是否有任何方法可以在有或没有 Linq 提供程序的情况下针对 DocumentDB 在 C# 中实现分页?

场景:我有一个支持分页的API,用户发送他们想要查看的页面以及一个pageSize,例如:

public virtual async Task<HttpResponseMessage> Get(int? page = DefaultPage, int? pageSize = DefaultPageSize)

然后我使用这些参数通过以下代码对数据访问层中的数据进行分页:

return query.Skip((pageNumber - 1) * pageSize).Take(pageSize);

"What is the problem then?",你可能会问。好吧,这种方法和代码在使用 EF 和 SQL 时工作得很好。问题是我想开始使用 DocumentDB,但他们的 Linq 实现不支持 Skip。我见过的唯一示例包括使用 TOP keyword or continuation tokens,它 非常适合我,允许用户发送 pageNumber 和 pageSize。

是否有任何实现仍允许我的用户在请求中提供 pageNumberpageSize

SKIP 是 SQL 的性能问题,NoSQL 由于其横向扩展设计而更糟。我们使用了 MongoDB 的 SKIP 功能,发现它实际上是从头开始重新运行查询,丢弃所有跳过的行。我们跳到列表的后面,查询花费的时间越长。因此,即使它具有 SKIP 功能,我们也不得不实施性能更高的解决方案。

DocumentDB 的产品经理明白这一点,并反对添加 SKIP。如果他们要做的话,我相信他们在添加TOP的时候就已经做到了。

对于 DocumentDB,最有效的方法是使用延续令牌并缓存所有结果,以达到(甚至超出预期)用户需要的位置。 Continuation token 会存活很长时间,因此您不需要立即获取所有页面。

虽然这并没有具体回答您的问题,但对于未来的 Google 员工,Document DB 支持通过延续标记进行分页。我写的很详细here。您需要的代码是:

var endpoint = "document db url";  
var primaryKey = "document db key";  
var client = new DocumentClient(new Uri(endpoint), primaryKey);  
var collection = UriFactory.CreateDocumentCollectionUri("database id", "collection id");

var options = new FeedOptions  
{ 
    MaxItemCount = 100 // <- Page size
};

var query = client.CreateDocumentQuery<Document>(collection, options).AsDocumentQuery();

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

    // Process paged results
}

我意识到这个问题已经有了一个可接受的(而且说得很好)答案,但是由于这个特定的 SO 页面是 Google 上 "DocumentDB skip" 的最高结果,我想我会在这里分享我的解决方案,这实际上只是 Larry 已经建议的实施。我在 Angular 中使用延续标记和缓存来为 DocumentDB 查询提出一个不错的分页机制。关键是我还允许排序和过滤,这减少了用户跳转到随机页面甚至结果最后一页的需要。这是我的解决方案:

http://www.zoeller.us/blog/2017/7/27/paging-results-with-documentdb