MongoDB Aggregation by Shifted Date - mongodb

Is there a way to aggregate by day, but over a 24 hour period that does not go from 12am - 11:59pm? A sample document looks like this:
{
date: ISODate("2012-11-02T17:04:11.102Z"),
user: 'testUser',
orders: 50
}
I need to aggregate the # of orders per user per day between 5 pm and 4:59:59.999 pm the next day. I can get the # of orders per user per day (over a 2 day range) using this:
db.hs.aggregate([{
$match: {
user: 'testUser',
date: {
$gte: new Date(2015,0,4,17,0,0,0),
$lt: new Date(2015,0,6,17,0,0,0)
}
}
}, {
$group: {
_id: {
date: {
month: {$month: "$date"},
day: {$dayOfMonth: "$date"},
year: {$year: "$date"}
},
user: "$user",
},
totord: {$sum: "$orders"}
}
}])
But this returns 3 results, one for Jan 4 after 5pm, one for Jan 5 all day, and one for Jan 6 before 5pm. I just don't know how to shift the aggregation to be between 5pm - 4:59pm.

I believe that you could use the $add aggregation operator on your dates in a $project aggregation step to get the desired result.
db.hs.aggregate([
{
$match: {
user: 'testUser',
date: {
$gte: new Date(2015,0,4,17,0,0,0),
$lt: new Date(2015,0,6,17,0,0,0)
}
}
}, {
$project: {
orders: 1,
user: 1,
date: { $add: [ "$date", 7*60*60000 ] }
}
}, {
$group: {
_id: {
date: {
month: { $month: "$date" },
day: { $dayOfMonth: "$date" },
year: { $year: "$date" }
},
user: "$user"
},
totord: {$sum: "$orders"}
}
}
])
I believe this should add 7 hours to the $date which should make it so anything after 5PM ends up after midnight the next day.

Related

Day wise + hour bucketing in mongo

I have a collection with a timestamp in each record. I need to aggregate the records of the collection per day of the week, and within it, on an hourly basis. I took a look at the aggregation / grouping queries here in SO, but I'm not sure how to use it in my scenario
Collection: Alerts
Docs:
{
isOpen: true,
Time: // ISO("time_string"),
...
...
}
I would like the aggs to be similar to how elasticsearch datetime histogram behaves.
Output:
{
day: "sunday",
time: "12am",
openAlerts: 23
},
{
day: "sunday",
time: "1am",
openAlerts: 13
},
{
day: "sunday",
time: "2am",
openAlerts: 0
},
Special emphasis on the 0 counts in the hour bucket. Is there a way to fill in 0s when there is no doc count?
Thanks
Would be like this:
db.collection.aggregate([
{
$group: {
_id: {
year: { $year: "$Time" },
month: { $month: "$Time" },
day: { $dayOfMonth: "$Time" },
hour: { $hour: "$Time" }
},
openAlerts: { $sum: 1 }
}
}
])

mongoDb get array of filter in one shot

I have mongo collection look like
{ day: '1', hour: 10:40 },
{ day: '1', hour: 08:40 },
{ day: '2', hour: 10:10 },
{ day: '2', hour: 08:30 },
I want to get this result.
[{day:'1', hours:['10:40','08:40']},
{day:'2', hours:['10:10','08:30']}]
I try to do this with query with out success to put in hours more than one field.
days= Model.aggregate
([{ $group: { _id: '$day', } }])
and then for each day
Model.find({day:days[0]})
If it's possible to do this in any prettier way.
I would like to know how :)
Use Aggregation Pipeline with $group and $project stages.
db.collection.aggregate([
{
$group: {
_id: "$day",
hours: {
$push: "$hour"
}
}
},
{
$project: {
_id: 0,
day: "$_id",
hours: "$hours"
}
}
])
https://mongoplayground.net/p/GBmNqfQv4Wp

Get Mongodb Documents for a given time range in a date range

I want to find out documents which exist between a certain time period for a given date range.
I have only a field "date" which is stored as a Date object.
For Example -
Find all documents with time between 10:00 am to 23:30 pm for dates ranging from 10th Jan 2018 to 30th Jan 2018
( Also I am currently using Version 3.4)
You can add temporary field which will represent minutes part of your date as 60*$hour + $minute, so it will be 600 for 10 am for instance and then apply your filtering conditions:
db.col.aggregate([
{
$addFields: {
minutes: {
$add: [ { $minute: "$date" }, { $multiply: [ { $hour: "$date" }, 60 ] }]
}
}
},
{
$match: {
$and: [
{ "date": { $gte: ISODate("2018-01-10T10:00:00.000Z") } },
{ "date" : { $lte: ISODate("2018-01-30T23:30:00.000Z") } },
{ "minutes": { $gte: 60*10 } },
{ "minutes": { $lte: 23*60+30 } }
]
}
},
{
$project: { minutes: 0 }
}
])
You can do this with the following code.
db.getCollection('collection name').aggregate([
{$project: {
"yearMonthDayUTC": { $dateToString: { format: "%Y-%m-%d", date: "$date" }},
"timewithOffset": { $dateToString: { format: "%H:%M:%S", date: "$date", timezone: "Your time zone" }}
}
},
{$match: {
"yearMonthDayUTC": {$gte: "2018-01-10", $lt: "2018-01-30"},
"timewithOffset": {$gte: "10:00:00", $lt: "23:30:00"}
}}
])

Mongodb need count for specific member id per day

Collection name : activity
What I need is activity count
of "memberId" = 123
where activity "type" = 'xxx'
per day
between "11/01/2015" and "11/15/2015" // from date and to date range
Expected Output:
[
{date:"2015-02-22",count:10},
{date:"2015-02-22",count:5},
]
I have no idea how to perform aggregate between dates and for a specific member id
where I am at is far far away from the solution :
db.activity.aggregate(
{ $project: {
date: {
years: {$year: '$dateInserted'},
months: {$month: '$dateInserted'},
days: {$dayOfMonth: '$dateInserted'},
},
memberId: '$memberId'
}},
{ $group: {
_id: { memberId: '$memberId', date: '$date' },
number: { $sum: 1}
}})
db.activity.aggregate([
{$match : { memberId : "xxx",item:"xyz",dateInserted: {$gte: ISODate("2013-01-01T00:00:00.0Z"), $lt: ISODate("2016-02-01T00:00:00.0Z")}}},
{$project: {day: {day: {$dayOfMonth: '$dateInserted'}, month: {$month: '$dateInserted'}, year: {$year: '$dateInserted'}}}},
{$group: { _id: { day: '$day' }, count: { $sum: 1} }},{ $sort:{_id:1}}
]);
Try that
You may need add $match stage before $project:
$match:
{dateInserted:{{$gte:new Date("2015-01-11T00:00:00 -02:00"),{$lte:new Date("2015-01-15T23:59:59 -02:00")}}},
{memberId:123},
{type:"xxx"}

Grouping by two fields in MongoDB?

I am attempting to get a count of records created on each day for the last 15 days. I came up with the query below:
db.users.aggregate(
{ $group: {
_id: {$dayOfYear: '$created'},
created: {$sum:1},
date: {$first: '$created'}
}
},
{$sort: {_id: 1}},
{$limit: 15}
);
Which almost works, but it will also count days from exactly a year ago. So if 2 records were created on 2/20/2014 and 3 were created on 2/20/2013 then a count of 5 would be returned (when all I want is 2). I was hoping to also group by the year like below:
db.users.aggregate(
{ $group: {
_id: {{$dayOfYear: '$created'},{$year: '$created'}},
created: {$sum:1},
date: {$first: '$created'}
}
},
{$sort: {_id: 1}},
{$limit: 15}
);
But this is a syntax error. How should I be attempting to count records created on a specific day?
db.users.aggregate(
{ $group: {
_id: {
day: { $dayOfYear: '$created' },
year: { $year: '$created' }
},
count: { $sum: 1 },
date: { $first: '$created' }
}
},
{ $project: { _id: 0, date: 1, count: 1 } }, // Only for more clear result.
{ $sort: { date: -1 } }, // If you want to view last 15 days - sort by descending.
{ $limit: 15 }
);