7

I have a mongo object with these fields:

DateTime TimeStamp;
float    Value;

How can I get the aggregation pipeline, in C#, with LINQ, to get the minimum, maximum and average of Value over a specific timestamp range?

I have seen a few aggregation examples, but I don't quite get it. Having an example on a simple case like this would certainly (hopefully) make me understand it.

0

2 Answers 2

8

You can use LINQ syntax which gets translated into Aggregation Framework's syntax. Assuming you have following Model class:

public class Model
{
    public DateTime Timestamp { get; set; }
    public float Value { get; set; }
}

you can use where to specify timestamp range and then use group with null as grouping key. MongoDB driver will translate Min, Max and Average from anonymous type into $max, $min and $avg from Aggregation Framework syntax

var q = from doc in Col.AsQueryable()
        where doc.Timestamp > DateTime.Now.AddDays(-3)
        where doc.Timestamp < DateTime.Now.AddDays(3)
        group doc by (Model)null into gr
        select new
        {
            Avg = (double)gr.Average(x => x.Value),
            Min = gr.Min(x => x.Value),
            Max = gr.Max(x => x.Value)
        };

var result = q.First();

List of accumulators supported by MongoDB driver can be found here.

EDIT: the (Model)null is required because the query has to be transformed to $group with _id set to null (docs) since you want to get one result with aggregates. Casting is required just for C# compiler purpose as doc is of type Model.

Sign up to request clarification or add additional context in comments.

3 Comments

can you explain the '(Model) null' part? I don't understand the null keyword there
an additional question: is is possible to do something, below the where, like: let Value = doc.Value and then group Value in order to not carry around the rest of the object?
@Thomas explained the null part in my edited answer. You can read more here (mongodb.github.io/mongo-csharp-driver/2.7/reference/driver/crud/…) about which LINQ operators are supported
3

The aggregation for this is done in two steps:

  1. $match - Retrieve documents with TimeStamp value between some defined minDate and maxDate.
  2. $group - Group on null. This will put all documents in a single group so we can apply an accumulator function across everything from the step 1 $match. The accumulator functions you're looking for are $min, $max, and $avg.

IMongoCollection<Entity> collection = GetMyCollection();

DateTime minDate = default(DateTime); // define this yourself
DateTime maxDate = default(DateTime); // define this yourself

var match = new BsonDocument
{ {
    "$match", new BsonDocument
    { {
        "TimeStamp", new BsonDocument
        { {
            "$and", new BsonDocument
            {
                { "$gt", minDate },
                { "$lt", maxDate }
            }
        } }
    } }
} };

var group = new BsonDocument
{ {
    "$group", new BsonDocument
    {
        { "_id", BsonNull.Value },
        { "min", new BsonDocument { { "$min", "Value" } } },
        { "max", new BsonDocument { { "$max", "Value" } } },
        { "avg", new BsonDocument { { "$avg", "Value" } } },
    }
} };

var result = collection.Aggregate(PipelineDefinition<Entity, BsonDocument>.Create(match, group)).Single();

double min = result["min"].AsDouble;
double max = result["max"].AsDouble;
double avg = result["avg"].AsDouble;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.