使用C#驱动程序分页MongoDB查询

时间:2015-12-29 22:52:58

标签: c# mongodb mongodb-.net-driver mongodb-csharp-2.0

我使用的是用于C#的2.2版MongoDB驱动程序。 我想分页查询:对查询的响应必须包含当前页面的项目以及与查询匹配的项目总数。

我想做一个查询。 使用mongo shell我可以意识到:

var c = db.mycol.find({....}).skip(0).limit(10)
var total = c.count();
while (c.hasNext()) {
   print(tojson(c.next()));
}

但是使用C#驱动程序,我不知道如何只使用一个查询。

var find = collection
  .Find(x => x.Valid == true)
  .Skip(0)
  .Limit(10);

var cursor = await find.ToCursorAsync(cancellationToken);
// How to get the count? There is no method in the IAsyncCursor interface.

有可能吗?一些想法?

2 个答案:

答案 0 :(得分:7)

您只能通过向DB发送一个查询来完成任务。通常的做法是遵循

var query = GetCollection().Find(x => x.Valid == true);
var totalTask = query.CountAsync();
var itemsTask = query.Skip(0).Limit(10).ToListAsync();
await Task.WhenAll(totalTask, itemsTask);
return new Page{ Total = totalTask.Result, Items = itemsTask.Result};

答案 1 :(得分:0)

在 MongoDB 中,我们能够创建一个数据处理管道,该管道将对我们的数据执行一次。

public class Person
{
    [BsonId]
    [BsonRepresentation(BsonType.String)]
    public string Id { get; set; }

    public string FirstName { get; set; }

    public string Surname { get; set; }
}

public class Peger
{
    public int Count { get; set; }

    public int Page { get; set; }

    public int Size { get; set; }

    public IEnumerable<Person> Items { get; set; }
}

class Program
{
    static async Task Main(string[] args)
    {
        var client = new MongoClient();
        var database = client.GetDatabase("pager_test");
        var collection = database.GetCollection<Person>(nameof(Person));

        int page = 1;
        int pageSize = 5;
        var results = await GetPagerResultAsync(page, pageSize, collection);
    }

    private static async Task<Peger> GetPagerResultAsync(int page, int pageSize, IMongoCollection<Person> collection)
    {
        // count facet, aggregation stage of count
        var countFacet = AggregateFacet.Create("countFacet",
            PipelineDefinition<Person, AggregateCountResult>.Create(new[]
            {
                PipelineStageDefinitionBuilder.Count<Person>()
            }));

        // data facet, we’ll use this to sort the data and do the skip and limiting of the results for the paging.
        var dataFacet = AggregateFacet.Create("dataFacet",
            PipelineDefinition<Person, Person>.Create(new[]
            {
                PipelineStageDefinitionBuilder.Sort(Builders<Person>.Sort.Ascending(x => x.Surname)),
                PipelineStageDefinitionBuilder.Skip<Person>((page - 1) * pageSize),
                PipelineStageDefinitionBuilder.Limit<Person>(pageSize),
            }));

        var filter = Builders<Person>.Filter.Empty;
        var aggregation = await collection.Aggregate()
            .Match(filter)
            .Facet(countFacet, dataFacet)
            .ToListAsync();

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

        var data = aggregation.First()
            .Facets.First(x => x.Name == "dataFacet")
            .Output<Person>();

        return new Pager
        {
            Count = (int)count / pageSize,
            Size = pageSize,
            Page = page,
            Items = data
        };
    }
}