Search code examples
c#.netmongodb-queryaggregationmongodb-.net-driver

MongoDB C# Driver GroupBy to get latest object of the same property. (With aggregation)


I have the following model of the collection "evaluations":

[BsonCollection("evaluations")]
public class Evaluation : Document
{
    [BsonRepresentation(BsonType.ObjectId)]
    public string AlertId { get; set; }

    public string EvaluationStatus { get; set; }

    public DateTime EvaluatedAt { get; set; }
}

What I would like to do is to retrieve a list with the last evaluation of each Alert object, which would mean grouping evaluations by AlertId then getting the latest EvaluatedAt of the group, and then return those evaluations.
With the result being a list of 'Evaluation' objects, (one evaluation per AlertId)

How would I construct that query using MongoDB driver with Aggregation?

Thanks for the help!


Solution

  • With a little research came up with this solution:

            var alertIds = alertss.Select(x => x.Id.ToString()).ToList();
    
            var sortByLatest = Builders<Evaluation>.Sort.Descending(x => x.EvaluatedAt);
    
            var groupByAlertId = new BsonDocument
                      {
                          { "_id", "$AlertId" },
                          { "EvaluationId", new BsonDocument { { "$first", "$_id" } } },
                          { "EvaluationStatus", new BsonDocument { { "$first", "$EvaluationStatus" } } },
                          { "EvaluatedAt", new BsonDocument { { "$first", "$EvaluatedAt" } } },
                      };
    
            ProjectionDefinition<BsonDocument> projection = new BsonDocument
                {
                    {"_id", "$EvaluationId"},
                    {"AlertId", "$_id"},
                    {"EvaluationStatus", "$EvaluationStatus"},
                    {"EvaluatedAt", "$EvaluatedAt"},
                };
    
            var evaluations = evaluationsRepository.GetCollection().Aggregate()
                .Match(x => alertIds.Contains(x.AlertId))
                .Sort(sortByLatest)
                .Group(groupByAlertId)
                .Project(projection)
                .As<Evaluation>().ToList();
    
            return evaluations;