如何解决带有 C# MongoDB 驱动程序的 AWS DocumentDB,不受支持的高效分页
我正在使用 C# MongoDB.Driver 2.12.4
MongoDB 一切都很好。不幸的是,我必须使用 AWS DocumentDB 作为生产数据库,它声称与 MongoDB 兼容,但我一直在发现几个问题:
- 索引有限https://docs.aws.amazon.com/documentdb/latest/developerguide/mongo-apis.html#mongo-apis-index
- 不支持排序索引或查询(已删除,设法通过其他方式进行不区分大小写的搜索)
- 它不支持 facet(我用它来高效分页)
"message": "Command aggregate failed: Aggregation stage not supported: '$facet'.",
问题是:使用 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 举报,一经查实,本站将立刻删除。