Search code examples
c#mongodbmongodb-querymongodb-.net-driver.net-7.0

Paging the result group by query MongoDB strongly typed C#


I am wondering if anyone can help me. I have created a query which returns duplicates grouped by an identifier and then pages the result-set (which works fine).

The advice I am seeking, is in regard to the most efficient way to get the total result count for the paging, whilst using the same filter. Can the query's be combined using count facet and data facet as oppose to the the way I have done below.

Working part

var filter = Builders<DuplicateOccurrence>.Filter.Eq(x => x.Id, occurrences.Id);

var data = await _baseRepository.DbCollection().Aggregate()
    .Match(filter)
    .SortByDescending(x => x.Identifier)
    .Group(e => e.Identifier, g => new 
    {
        Identifier= g.Key,
        Occurred = g.Select(x => new 
        {
            Id = x.Id
        })
    })
    .Skip((occurrences.CurrentPage - 1) * occurrences.PageSize)
    .Limit(occurrences.PageSize)
    .ToListAsync(cancellationToken);

Seeking advice of getting total count

var count = _baseRepository.DbCollection()
    .AsQueryable()
    .Where(x=> x.DetectionReportId == occurrences.DetectionReportObjectId)
    .GroupBy(s => s.Identifier)
    .Count();

Solution

  • If you want to get the total count of elements matching the filer, you can split your query in two.

    var filter = Builders<DuplicateOccurrence>.Filter.Eq(x => x.Id, occurrences.Id);
    
    // first create the query that will filter and group the documents
    var query = await _baseRepository.DbCollection()
        .Aggregate()
        .Match(filter)
        .Group(e => e.Identifier, g => new 
        {
            Identifier= g.Key,
            Occurred = g.Select(x => new { Id = x.Id })
        });
    
    // get the total count of documents
    var totalDocs = query.Count();
    
    // get the documents for the current page
    var documents = await query
       .SortByDescending(x => x.Identifier)
       .Skip((occurrences.CurrentPage - 1) * occurrences.PageSize)
       .Limit(occurrences.PageSize)
       .ToListAsync(cancellationToken);
    

    You can also use LINQ to achieve the same result, but there is no overload that takes projection for the groups:

    var query = await _baseRepository.DbCollection()
        .AsQueryable()
        .Where(x => x.Id, occurrences.Id)
        .GroupBy(e => e.Identifier);
        
    var totalDocs = await query.CountAsync();
    
    var documents = await query
        .OrderByDescending(x => x.Identifier)
        .Skip((occurrences.CurrentPage - 1) * occurrences.PageSize)
        .Take(occurrences.PageSize)
        .ToListAsync(cancellationToken)