Reputation: 3018
Using C# MongoDb driver.
I have a Login collection which stores the last logins to the system.
I would like to group them into 2 groups: the last 24 hours and the last hour.
The object looks like that:
public sealed class Login
{
[BsonId]
public ObjectId UserId;
public DateTime LastLogin;
}
Each user, as you may deduct, has only 1 row.
The expected result would look something like :
{
"Id" : "24Hours", "Count" : <some number>,
"Id" : "LastHour", "Count" : <some other number>
}
I have no experience with Aggregation and all of the example Ive seen on Wiki were all on grouping common fields, here I have data manipulation so I dont have the tools.
It would be nice if I'll be able to use AggregateAsync
instead of Aggregate
.
Upvotes: 0
Views: 477
Reputation: 16968
I can use projection and gtoup in c# like this:
var yesterday = DateTime.Now.AddDays(-1);
var lastHour = DateTime.Now.AddHours(-1);
var projection = new BsonDocument
{
{
"Last24Hours",
new BsonDocument("$cond",
new BsonArray {new BsonDocument("$gte", new BsonArray {"$LastLogin", yesterday}), 1, 0})
},
{
"LastHour",
new BsonDocument("$cond",
new BsonArray {new BsonDocument("$gte", new BsonArray {"$LastLogin", lastHour}), 1, 0})
}
};
var groupBy = new BsonDocument
{
{"_id", BsonNull.Value},
{"CountLast24Hours", new BsonDocument("$sum", "$Last24Hours")},
{"CountLastHour", new BsonDocument("$sum", "$LastHour")}
};
And get result by using a pipeline like this:
var pipeline = PipelineDefinition<Login, BsonDocument>.Create(
new BsonDocument("$project", projection),
new BsonDocument("$group", groupBy),
);
var result = col.Aggregate(pipeline).SingleOrDefault();
var countLast24Hours = result["CountLast24Hours"].AsInt32;
var countLastHour = result["CountLastHour"].AsInt32;
Upvotes: 1
Reputation: 9679
I have managed to do this with Aggregation framework. What i couldn't do is to convert bool flag, if login was within 24 hours to name, i did it with extra Select
.
First we get all logins within last 24 hours, than we group results depending on if they were in last hour or nor (true/false), after that we get whole result as enumerable and perfome fine tuning on name, i have described before.
var result =
collection.Aggregate()
.Match(x => x.LastLogin >= DateTime.Now.AddDays(-1) && x.LastLogin <= DateTime.Now)
.Group(r => r.LastLogin <= DateTime.Now.AddHours(-1), r =>
new { WithinLastHour = r.Key , Count = r.Count()})
.ToEnumerable()
.Select(x=>
new {Name = x.WithinLastHour ? "Within last hour":"Within last 24 hours",
x.Count})
.ToList();
Sure, you could do AggregateAsync
if you want.
Upvotes: 1