带有 C# MongoDB 驱动程序的 AWS DocumentDB,不受支持的高效分页

问题描述

我正在使用 C# MongoDB.Driver 2.12.4

针对 MongoDB 4.0 开发一些查询和索引

MongoDB 一切都很好。不幸的是,我必须使用 AWS DocumentDB 作为生产数据库,它声称与 MongoDB 兼容,但我一直在发现几个问题:

问题是:使用 AWS DocumentDB 对结果进行分页的最佳方法是什么?是否有任何选项可以通过单个查询做到这一点?或者我必须两次访问数据库

这是我使用 Facet 和聚合 facet 结果的原始实现。

public async Task<PagedResult<TDocument>> GetAll<TDocument>(
    Expression<Func<TDocument,bool>> filter,Sort<TDocument> sort,Pagination pagination,CancellationToken cancellationToken = new())
    where TDocument : class,IDocument
{
    filter ??= doc => true;
    sort ??= Sort<TDocument>.Default;
    if (pagination == null) throw new ArgumentNullException(nameof(pagination));

    var collection = _collectionRetrieverService.GetCollection<TDocument>();

    var sortDeFinition = GetSortDeFinition(sort);
    
    var pageNumber = pagination.PageNumber;
    var pageSize = pagination.PageSize;

    var countPipelineDeFinition =
        PipelineDeFinition<TDocument,AggregateCountResult>
            .Create(new[]
            {
                PipelinestageDeFinitionBuilder.Count<TDocument>()
            });
    
    var dataPipelineDeFinition =
        PipelineDeFinition<TDocument,TDocument>
            .Create(new[]
            {
                PipelinestageDeFinitionBuilder.sort(sortDeFinition),PipelinestageDeFinitionBuilder.Skip<TDocument>((pageNumber -1) * pageSize),PipelinestageDeFinitionBuilder.Limit<TDocument>(pageSize)
            });

    const string countFacetName = "count";
    const string dataFacetName = "data";
    
    var countFacet = AggregateFacet.Create(countFacetName,countPipelineDeFinition);
    var dataFacet = AggregateFacet.Create(dataFacetName,dataPipelineDeFinition);

    var aggregateOptions =
        new AggregateOptions
        {
            // Collation is not currently supported in AWS DocumentDB. See https://docs.aws.amazon.com/documentdb/latest/developerguide/mongo-apis.html#mongo-apis-index
            //Collation = Collationoptions.CaseInsensitiveCollation
        };
    
    var aggregation =
        await collection
            .Aggregate(aggregateOptions)
            .Match(filter)
            .Facet(countFacet,dataFacet)
            .ToListAsync(cancellationToken);

    var count =
        aggregation
            .First()
            .Facets
            .First(x => x.Name == countFacetName)
            .Output<AggregateCountResult>()
            ?.FirstOrDefault()
            ?.Count;

    if (count is null)
    {
        var emptyResult =
            new PagedResult<TDocument>()
            {
                Items = Enumerable.Empty<TDocument>(),PageNumber = pageNumber,PageSize = pageSize,TotalPages = pageNumber,TotalCount = 0
            };
        return emptyResult;
    }
    
    var totalPages = (int)Math.Ceiling((double)count/ pageSize);

    var data =
        aggregation
            .First()
            .Facets
            .First(x => x.Name == dataFacetName)
            .Output<TDocument>();

    var result =
        new PagedResult<TDocument>
        {
            Items = data,TotalPages = totalPages,TotalCount = count.Value
        };

    return result;
}

更新 2021-07-06

这是我的解决方法,它查询了两次数据库,因为我需要匹配过滤条件的项目总数。

public async Task<PagedResult<TDocument>> GetAll<TDocument>(
    Expression<Func<TDocument,IDocument
{
    filter ??= doc => true;
    sort ??= Sort<TDocument>.Default;
    if (pagination == null) throw new ArgumentNullException(nameof(pagination));

    var collection = _collectionRetrieverService.GetCollection<TDocument>();

    var sortDeFinition = GetSortDeFinition(sort);
    
    var pageNumber = pagination.PageNumber;
    var pageSize = pagination.PageSize;
    
    var skipCount = pageSize * (pageNumber - 1);
    
    var count = await collection.CountDocumentsAsync(filter,cancellationToken: cancellationToken);
    
    if (count == 0)
    {
        var emptyResult =
            new PagedResult<TDocument>()
            {
                Items = Enumerable.Empty<TDocument>(),TotalCount = count
            };
        return emptyResult;
    }
    
    var totalPages = (int)Math.Ceiling((double)count/ pageSize);
    
    var findOptions =
        new FindOptions<TDocument,TDocument>
        {
            AllowPartialResults = false,Sort = sortDeFinition,Limit = pageSize,Skip = skipCount
            // Collation is not currently supported in AWS DocumentDB. See https://docs.aws.amazon.com/documentdb/latest/developerguide/mongo-apis.html#mongo-apis-index
            //Collation = Collationoptions.CaseInsensitiveCollation
        };
    var queryResult = await collection.FindAsync(filter,findOptions,cancellationToken);
    var results = await queryResult.ToListAsync(cancellationToken: cancellationToken);
    
    var result =
        new PagedResult<TDocument>
        {
            Items = results,TotalCount = count
        };

    return result;
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)