15

C# 用の MongoDB ドライバーのバージョン 2.2 を使用しています。クエリをページ分割したい : クエリへの応答には、現在のページのアイテムと、クエリに一致するアイテムの総数が含まれている必要があります。

1つのクエリを実行したい。mongo シェルを使用すると、次のように実現できます。

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

しかし、C# ドライバーでは、1 つのクエリだけでそれを行う方法がわかりません。

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.

出来ますか ?いくつかのアイデア?

4

2 に答える 2

18

クエリを 1 つだけ 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};
于 2015-12-30T15:52:15.003 に答える
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
        };
    }
}
于 2021-02-06T09:04:42.753 に答える