Group result by 15 minutes time interval in MongoDbmongodb aggregrate timestamp by 10 minute intervalsQuery datetime by time of day in MongoDBMongoose aggregation groupby on day,week,yearaggregate group by time of intervals of 15 minutesMongoDB aggregation convert NumberInt32 to ISODategrouping by hour in $group (aggregation)MongoDB last month averagemongodb: aggregation for every hour between two datesconvert date to timestamp(10 or 13 digit) in MongodbHow to group the mondoDB document data by timestamp as quarterly/half yearlyMongoDB or CouchDB - fit for production?MongoDB vs. CassandraFind objects between two dates MongoDBHow to query MongoDB with “like”?Delete everything in a MongoDB databaseUpdate MongoDB field using value of another fieldRetrieve only the queried element in an object array in MongoDB collectionMongoDB: Combine data from multiple collections into one..how?How do I drop a MongoDB database from the command line?When to use CouchDB over MongoDB and vice versa
Very lazy puppy
Persuading players to be less attached to a pre-session 0 character concept
Is there an in-universe reason Harry says this or is this simply a Rowling mistake?
Are all article combinations valid patterns for "the" ɴᴏᴜɴ of "the" ɴᴏᴜɴ?
Plausibility and performance of a composite longbow
Microservices and Stored Procedures
What exactly is a web font, and what does converting to one involve?
Can Brexit be undone in an emergency?
What is the origin of the "being immortal sucks" trope?
Preventing the ears from getting clogged on descent to Barcelona
Should I inform my future product owner that there is a good chance that a team member will leave the company soon?
What is the origin of the “clerics can create water” trope?
Unpredictability of Stock Market
Abilities interrupting effects on a cast card
What is Cousin Itt in The Addams Family?
How do you determine which representation of a function to use for Newton's method?
How to convey to the people around me that I want to disengage myself from constant giving?
Delete empty subfolders, keep parent folder
What's the purpose of autocorrelation?
What was the earliest microcomputer Logo language implementation?
Can a business put whatever they want into a contract?
Is it possible that the shadow of The Moon is a single dot during solar eclipse?
Is it safe to put a microwave in a walk-in closet?
Do household ovens ventilate heat to the outdoors?
Group result by 15 minutes time interval in MongoDb
mongodb aggregrate timestamp by 10 minute intervalsQuery datetime by time of day in MongoDBMongoose aggregation groupby on day,week,yearaggregate group by time of intervals of 15 minutesMongoDB aggregation convert NumberInt32 to ISODategrouping by hour in $group (aggregation)MongoDB last month averagemongodb: aggregation for every hour between two datesconvert date to timestamp(10 or 13 digit) in MongodbHow to group the mondoDB document data by timestamp as quarterly/half yearlyMongoDB or CouchDB - fit for production?MongoDB vs. CassandraFind objects between two dates MongoDBHow to query MongoDB with “like”?Delete everything in a MongoDB databaseUpdate MongoDB field using value of another fieldRetrieve only the queried element in an object array in MongoDB collectionMongoDB: Combine data from multiple collections into one..how?How do I drop a MongoDB database from the command line?When to use CouchDB over MongoDB and vice versa
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
I have a "status" collection like this strcture -
_id: ObjectId("545a0b63b03dbcd1238b4567"),
status: 1004,
comment: "Rem dolor ipsam placeat omnis non. Aspernatur nobis qui nisi similique.",
created_at: ISODate("2014-11-05T11:34:59.804Z")
,
_id: ObjectId("545a0b66b03dbcd1238b4568"),
status: 1001,
comment: "Sint et eos vero ipsa voluptatem harum. Hic unde voluptatibus et blanditiis quod modi.",
created_at: ISODate("2014-11-05T11:35:02.814Z")
....
....
I need to get result grouped by 15 minutes interval from that collection.
mongodb mongodb-query aggregation-framework
add a comment
|
I have a "status" collection like this strcture -
_id: ObjectId("545a0b63b03dbcd1238b4567"),
status: 1004,
comment: "Rem dolor ipsam placeat omnis non. Aspernatur nobis qui nisi similique.",
created_at: ISODate("2014-11-05T11:34:59.804Z")
,
_id: ObjectId("545a0b66b03dbcd1238b4568"),
status: 1001,
comment: "Sint et eos vero ipsa voluptatem harum. Hic unde voluptatibus et blanditiis quod modi.",
created_at: ISODate("2014-11-05T11:35:02.814Z")
....
....
I need to get result grouped by 15 minutes interval from that collection.
mongodb mongodb-query aggregation-framework
12
Is their something in the provided answer that is unclear or does not apply to your situation? Noting that it is still not accepted.
– Neil Lunn
Nov 13 '14 at 7:54
3
Don't bother, he already took answer, why bother yourself with accepting answers.
– nurgasemetey
Aug 26 '16 at 21:07
add a comment
|
I have a "status" collection like this strcture -
_id: ObjectId("545a0b63b03dbcd1238b4567"),
status: 1004,
comment: "Rem dolor ipsam placeat omnis non. Aspernatur nobis qui nisi similique.",
created_at: ISODate("2014-11-05T11:34:59.804Z")
,
_id: ObjectId("545a0b66b03dbcd1238b4568"),
status: 1001,
comment: "Sint et eos vero ipsa voluptatem harum. Hic unde voluptatibus et blanditiis quod modi.",
created_at: ISODate("2014-11-05T11:35:02.814Z")
....
....
I need to get result grouped by 15 minutes interval from that collection.
mongodb mongodb-query aggregation-framework
I have a "status" collection like this strcture -
_id: ObjectId("545a0b63b03dbcd1238b4567"),
status: 1004,
comment: "Rem dolor ipsam placeat omnis non. Aspernatur nobis qui nisi similique.",
created_at: ISODate("2014-11-05T11:34:59.804Z")
,
_id: ObjectId("545a0b66b03dbcd1238b4568"),
status: 1001,
comment: "Sint et eos vero ipsa voluptatem harum. Hic unde voluptatibus et blanditiis quod modi.",
created_at: ISODate("2014-11-05T11:35:02.814Z")
....
....
I need to get result grouped by 15 minutes interval from that collection.
mongodb mongodb-query aggregation-framework
mongodb mongodb-query aggregation-framework
edited Nov 8 '14 at 6:31
Neil Lunn
107k24 gold badges199 silver badges200 bronze badges
107k24 gold badges199 silver badges200 bronze badges
asked Nov 8 '14 at 6:18
Hein Zaw HtetHein Zaw Htet
4061 gold badge6 silver badges15 bronze badges
4061 gold badge6 silver badges15 bronze badges
12
Is their something in the provided answer that is unclear or does not apply to your situation? Noting that it is still not accepted.
– Neil Lunn
Nov 13 '14 at 7:54
3
Don't bother, he already took answer, why bother yourself with accepting answers.
– nurgasemetey
Aug 26 '16 at 21:07
add a comment
|
12
Is their something in the provided answer that is unclear or does not apply to your situation? Noting that it is still not accepted.
– Neil Lunn
Nov 13 '14 at 7:54
3
Don't bother, he already took answer, why bother yourself with accepting answers.
– nurgasemetey
Aug 26 '16 at 21:07
12
12
Is their something in the provided answer that is unclear or does not apply to your situation? Noting that it is still not accepted.
– Neil Lunn
Nov 13 '14 at 7:54
Is their something in the provided answer that is unclear or does not apply to your situation? Noting that it is still not accepted.
– Neil Lunn
Nov 13 '14 at 7:54
3
3
Don't bother, he already took answer, why bother yourself with accepting answers.
– nurgasemetey
Aug 26 '16 at 21:07
Don't bother, he already took answer, why bother yourself with accepting answers.
– nurgasemetey
Aug 26 '16 at 21:07
add a comment
|
5 Answers
5
active
oldest
votes
There are a couple of ways to do this.
The first is with Date Aggregation Operators, which allow you to dissect the "date" values in documents. Specifically for "grouping" as the primary intent:
db.collection.aggregate([
"$group":
"_id":
"year": "$year": "$created_at" ,
"dayOfYear": "$dayOfYear": "$created_at" ,
"hour": "$hour": "$created_at" ,
"interval":
"$subtract": [
"$minute": "$created_at" ,
"$mod": [ "$minute": "$created_at", 15]
]
,
"count": "$sum": 1
}
])
The second way is by using a little trick of when a date object is subtracted (or other direct math operation) from another date object, then the result is a numeric value representing the epoch timestamp milliseconds between the two objects. So just using the epoch date you get the epoch milliseconds representation. Then use date math for the interval:
db.collection.aggregate([
"$group":
"_id":
"$subtract": [
"$subtract": [ "$created_at", new Date("1970-01-01") ] ,
"$mod": [
"$subtract": [ "$created_at", new Date("1970-01-01") ] ,
1000 * 60 * 15
]
]
,
"count": "$sum": 1
])
So it depends on what kind of output format you want for the grouping interval. Both basically represent the same thing and have sufficient data to re-construct as a "date" object in your code.
You can put anything else you want in the "grouping operator" portion after the grouping _id
. I'm just using the basic "count" example in lieu of any real statement from yourself as to what you really want to do.
MongoDB 4.x and Upwards
There were some additions to Date Aggregation Operators since the original writing, but from MongoDB 4.0 there will be actual "real casting of types" as opposed to the basic math tricks done here with BSON Date conversion.
For instance we can use $toLong
and $toDate
as new helpers here:
db.collection.aggregate([
"$group":
"_id":
"$toDate":
"$subtract": [
"$toLong": "$created_at" ,
"$mod": [ "$toLong": "$created_at" , 1000 * 60 * 15 ]
]
,
"count": "$sum": 1
])
That's a bit shorter and does not require defining an external BSON Date for the "epoch" value as a constant in defining the pipeline so it's pretty consistent for all language implementations.
Those are just two of the "helper" methods for type conversion which all tie back to the $convert
method, which is a "longer" form of the implementation allowing for custom handling on null
or error in conversion.
It's even possible with such casting to get the Date
information from the ObjectId
of the primary key, as this would be a reliable source of "creation" date:
db.collection.aggregate([
"$group":
"_id":
"$toDate":
"$subtract": [
"$toLong": "$toDate": "$_id" ,
"$mod": [ "$toLong": "$toDate": "$_id" , 1000 * 60 * 15 ]
]
,
"count": "$sum": 1
])
So "casting types" with this sort of conversion can be pretty powerful tool.
Warning -
ObjectId
values are limited to precision to the second only for the internal time value that makes up part of their data allowing the$toDate
conversion. The actual inserted "time" is most probably dependent on the driver in use. Where precision is required, it's still recommended to use a discrete BSON Date field instead of relying onObjectId
values.
9
too bad i can't accept for him - really useful answer !
– Petrov
Mar 28 '15 at 19:44
2
i couldn't agree more @Petrov
– aiapatag
Aug 27 '15 at 10:24
2
Thanks for providing these good solutions! I think there might be a small error in your first example. You are missing the grouping by hour (in order to retrieve the 15 minutes intereval – which I assume – should be by the hour). So you would need to add"hour": "$hour": "$created_at" ,
after thedayOfYear
-line
– skofgar
Jul 19 '17 at 23:25
Mongodb 4.0 has released in 2018 and you know these aggregations from 2014... How ???
– Ashh
Jul 20 '18 at 17:25
1
@AnthonyWinzlet, he edited his answer on 26 Apr 2018.
– Paul
Aug 25 '18 at 14:20
add a comment
|
I like the other answer here, and mostly for the use of date math instead of aggregation date operators which while helpful can also be a little obscure.
The only thing I want to add here is that you can also return a Date
object from the aggregation framework by this approach as opposed to the "numeric" timestamp as the result. It's just a little extra math on the same principles, using $add
:
db.collection.aggregate([
"$group":
"_id":
"$add": [
"$subtract": [
"$subtract": [ "$current_date", new Date(0) ] ,
"$mod": [
"$subtract": [ "$current_date", new Date(0) ] ,
1000 * 60 * 15
]
] ,
new Date(0)
]
,
"count": "$sum": 1
])
The Date(0)
contructs in JavaScript here represent the same "epoch" date in a shorter form, as 0 millisecond from epoch is epoch. But the main point is that when the "addition" to another BSON date object is done with a numeric identifier, then the inverse of the described condition is true and the end result is actually now a Date
.
All drivers will return the native Date
type to their language by this approach.
add a comment
|
A little more beautiful for mongo db.version() < 3.0
db.collection.aggregate([
$match: created_at:$exists:1,
$group:
_id: $add:[
$dayOfYear: "$created_at" ,
$multiply: [$year: "$created_at", 1000]
],
count: $sum: 1
,
$sort:_id:-1
])
add a comment
|
Another useful way:
db.collection.aggregate([
$group:
_id:
overallTime:
$dateToString: format: "%Y-%m-%dT%H", date: "$created_at"
,
interval: $trunc: $divide: [ $minute: "$created_at" , 15 ]
,
,
])
And more easier for min, hour, day intervals:
var format = "%Y-%m-%dT%H:%M"; // 1 min
var format = "%Y-%m-%dT%H"; // 1 hour
var format = "%Y-%m-%d"; // 1 day
db.collection.aggregate([
$group:
_id: $dateToString: format: format, date: "$created_at" ,
,
])
add a comment
|
@Neil Lunn's answer at https://stackoverflow.com/a/26814496/8474325 for MongoDb 4.x upwards is fantastic. But there is a small mistake in the code where he uses ObjectId for the aggregation. The Line "$toDate": "_id"
has to be changed to "$toDate": "$_id"
for the code to work.
Here's the corrected code.
db.collection.aggregate([
"$group":
"_id":
"$toDate":
"$subtract": [
"$toLong": "$toDate": "$_id" ,
"$mod": [ "$toLong": "$toDate": "$_id" , 1000 * 60 * 15 ]
]
,
"count": "$sum": 1
])
add a comment
|
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f26814427%2fgroup-result-by-15-minutes-time-interval-in-mongodb%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
There are a couple of ways to do this.
The first is with Date Aggregation Operators, which allow you to dissect the "date" values in documents. Specifically for "grouping" as the primary intent:
db.collection.aggregate([
"$group":
"_id":
"year": "$year": "$created_at" ,
"dayOfYear": "$dayOfYear": "$created_at" ,
"hour": "$hour": "$created_at" ,
"interval":
"$subtract": [
"$minute": "$created_at" ,
"$mod": [ "$minute": "$created_at", 15]
]
,
"count": "$sum": 1
}
])
The second way is by using a little trick of when a date object is subtracted (or other direct math operation) from another date object, then the result is a numeric value representing the epoch timestamp milliseconds between the two objects. So just using the epoch date you get the epoch milliseconds representation. Then use date math for the interval:
db.collection.aggregate([
"$group":
"_id":
"$subtract": [
"$subtract": [ "$created_at", new Date("1970-01-01") ] ,
"$mod": [
"$subtract": [ "$created_at", new Date("1970-01-01") ] ,
1000 * 60 * 15
]
]
,
"count": "$sum": 1
])
So it depends on what kind of output format you want for the grouping interval. Both basically represent the same thing and have sufficient data to re-construct as a "date" object in your code.
You can put anything else you want in the "grouping operator" portion after the grouping _id
. I'm just using the basic "count" example in lieu of any real statement from yourself as to what you really want to do.
MongoDB 4.x and Upwards
There were some additions to Date Aggregation Operators since the original writing, but from MongoDB 4.0 there will be actual "real casting of types" as opposed to the basic math tricks done here with BSON Date conversion.
For instance we can use $toLong
and $toDate
as new helpers here:
db.collection.aggregate([
"$group":
"_id":
"$toDate":
"$subtract": [
"$toLong": "$created_at" ,
"$mod": [ "$toLong": "$created_at" , 1000 * 60 * 15 ]
]
,
"count": "$sum": 1
])
That's a bit shorter and does not require defining an external BSON Date for the "epoch" value as a constant in defining the pipeline so it's pretty consistent for all language implementations.
Those are just two of the "helper" methods for type conversion which all tie back to the $convert
method, which is a "longer" form of the implementation allowing for custom handling on null
or error in conversion.
It's even possible with such casting to get the Date
information from the ObjectId
of the primary key, as this would be a reliable source of "creation" date:
db.collection.aggregate([
"$group":
"_id":
"$toDate":
"$subtract": [
"$toLong": "$toDate": "$_id" ,
"$mod": [ "$toLong": "$toDate": "$_id" , 1000 * 60 * 15 ]
]
,
"count": "$sum": 1
])
So "casting types" with this sort of conversion can be pretty powerful tool.
Warning -
ObjectId
values are limited to precision to the second only for the internal time value that makes up part of their data allowing the$toDate
conversion. The actual inserted "time" is most probably dependent on the driver in use. Where precision is required, it's still recommended to use a discrete BSON Date field instead of relying onObjectId
values.
9
too bad i can't accept for him - really useful answer !
– Petrov
Mar 28 '15 at 19:44
2
i couldn't agree more @Petrov
– aiapatag
Aug 27 '15 at 10:24
2
Thanks for providing these good solutions! I think there might be a small error in your first example. You are missing the grouping by hour (in order to retrieve the 15 minutes intereval – which I assume – should be by the hour). So you would need to add"hour": "$hour": "$created_at" ,
after thedayOfYear
-line
– skofgar
Jul 19 '17 at 23:25
Mongodb 4.0 has released in 2018 and you know these aggregations from 2014... How ???
– Ashh
Jul 20 '18 at 17:25
1
@AnthonyWinzlet, he edited his answer on 26 Apr 2018.
– Paul
Aug 25 '18 at 14:20
add a comment
|
There are a couple of ways to do this.
The first is with Date Aggregation Operators, which allow you to dissect the "date" values in documents. Specifically for "grouping" as the primary intent:
db.collection.aggregate([
"$group":
"_id":
"year": "$year": "$created_at" ,
"dayOfYear": "$dayOfYear": "$created_at" ,
"hour": "$hour": "$created_at" ,
"interval":
"$subtract": [
"$minute": "$created_at" ,
"$mod": [ "$minute": "$created_at", 15]
]
,
"count": "$sum": 1
}
])
The second way is by using a little trick of when a date object is subtracted (or other direct math operation) from another date object, then the result is a numeric value representing the epoch timestamp milliseconds between the two objects. So just using the epoch date you get the epoch milliseconds representation. Then use date math for the interval:
db.collection.aggregate([
"$group":
"_id":
"$subtract": [
"$subtract": [ "$created_at", new Date("1970-01-01") ] ,
"$mod": [
"$subtract": [ "$created_at", new Date("1970-01-01") ] ,
1000 * 60 * 15
]
]
,
"count": "$sum": 1
])
So it depends on what kind of output format you want for the grouping interval. Both basically represent the same thing and have sufficient data to re-construct as a "date" object in your code.
You can put anything else you want in the "grouping operator" portion after the grouping _id
. I'm just using the basic "count" example in lieu of any real statement from yourself as to what you really want to do.
MongoDB 4.x and Upwards
There were some additions to Date Aggregation Operators since the original writing, but from MongoDB 4.0 there will be actual "real casting of types" as opposed to the basic math tricks done here with BSON Date conversion.
For instance we can use $toLong
and $toDate
as new helpers here:
db.collection.aggregate([
"$group":
"_id":
"$toDate":
"$subtract": [
"$toLong": "$created_at" ,
"$mod": [ "$toLong": "$created_at" , 1000 * 60 * 15 ]
]
,
"count": "$sum": 1
])
That's a bit shorter and does not require defining an external BSON Date for the "epoch" value as a constant in defining the pipeline so it's pretty consistent for all language implementations.
Those are just two of the "helper" methods for type conversion which all tie back to the $convert
method, which is a "longer" form of the implementation allowing for custom handling on null
or error in conversion.
It's even possible with such casting to get the Date
information from the ObjectId
of the primary key, as this would be a reliable source of "creation" date:
db.collection.aggregate([
"$group":
"_id":
"$toDate":
"$subtract": [
"$toLong": "$toDate": "$_id" ,
"$mod": [ "$toLong": "$toDate": "$_id" , 1000 * 60 * 15 ]
]
,
"count": "$sum": 1
])
So "casting types" with this sort of conversion can be pretty powerful tool.
Warning -
ObjectId
values are limited to precision to the second only for the internal time value that makes up part of their data allowing the$toDate
conversion. The actual inserted "time" is most probably dependent on the driver in use. Where precision is required, it's still recommended to use a discrete BSON Date field instead of relying onObjectId
values.
9
too bad i can't accept for him - really useful answer !
– Petrov
Mar 28 '15 at 19:44
2
i couldn't agree more @Petrov
– aiapatag
Aug 27 '15 at 10:24
2
Thanks for providing these good solutions! I think there might be a small error in your first example. You are missing the grouping by hour (in order to retrieve the 15 minutes intereval – which I assume – should be by the hour). So you would need to add"hour": "$hour": "$created_at" ,
after thedayOfYear
-line
– skofgar
Jul 19 '17 at 23:25
Mongodb 4.0 has released in 2018 and you know these aggregations from 2014... How ???
– Ashh
Jul 20 '18 at 17:25
1
@AnthonyWinzlet, he edited his answer on 26 Apr 2018.
– Paul
Aug 25 '18 at 14:20
add a comment
|
There are a couple of ways to do this.
The first is with Date Aggregation Operators, which allow you to dissect the "date" values in documents. Specifically for "grouping" as the primary intent:
db.collection.aggregate([
"$group":
"_id":
"year": "$year": "$created_at" ,
"dayOfYear": "$dayOfYear": "$created_at" ,
"hour": "$hour": "$created_at" ,
"interval":
"$subtract": [
"$minute": "$created_at" ,
"$mod": [ "$minute": "$created_at", 15]
]
,
"count": "$sum": 1
}
])
The second way is by using a little trick of when a date object is subtracted (or other direct math operation) from another date object, then the result is a numeric value representing the epoch timestamp milliseconds between the two objects. So just using the epoch date you get the epoch milliseconds representation. Then use date math for the interval:
db.collection.aggregate([
"$group":
"_id":
"$subtract": [
"$subtract": [ "$created_at", new Date("1970-01-01") ] ,
"$mod": [
"$subtract": [ "$created_at", new Date("1970-01-01") ] ,
1000 * 60 * 15
]
]
,
"count": "$sum": 1
])
So it depends on what kind of output format you want for the grouping interval. Both basically represent the same thing and have sufficient data to re-construct as a "date" object in your code.
You can put anything else you want in the "grouping operator" portion after the grouping _id
. I'm just using the basic "count" example in lieu of any real statement from yourself as to what you really want to do.
MongoDB 4.x and Upwards
There were some additions to Date Aggregation Operators since the original writing, but from MongoDB 4.0 there will be actual "real casting of types" as opposed to the basic math tricks done here with BSON Date conversion.
For instance we can use $toLong
and $toDate
as new helpers here:
db.collection.aggregate([
"$group":
"_id":
"$toDate":
"$subtract": [
"$toLong": "$created_at" ,
"$mod": [ "$toLong": "$created_at" , 1000 * 60 * 15 ]
]
,
"count": "$sum": 1
])
That's a bit shorter and does not require defining an external BSON Date for the "epoch" value as a constant in defining the pipeline so it's pretty consistent for all language implementations.
Those are just two of the "helper" methods for type conversion which all tie back to the $convert
method, which is a "longer" form of the implementation allowing for custom handling on null
or error in conversion.
It's even possible with such casting to get the Date
information from the ObjectId
of the primary key, as this would be a reliable source of "creation" date:
db.collection.aggregate([
"$group":
"_id":
"$toDate":
"$subtract": [
"$toLong": "$toDate": "$_id" ,
"$mod": [ "$toLong": "$toDate": "$_id" , 1000 * 60 * 15 ]
]
,
"count": "$sum": 1
])
So "casting types" with this sort of conversion can be pretty powerful tool.
Warning -
ObjectId
values are limited to precision to the second only for the internal time value that makes up part of their data allowing the$toDate
conversion. The actual inserted "time" is most probably dependent on the driver in use. Where precision is required, it's still recommended to use a discrete BSON Date field instead of relying onObjectId
values.
There are a couple of ways to do this.
The first is with Date Aggregation Operators, which allow you to dissect the "date" values in documents. Specifically for "grouping" as the primary intent:
db.collection.aggregate([
"$group":
"_id":
"year": "$year": "$created_at" ,
"dayOfYear": "$dayOfYear": "$created_at" ,
"hour": "$hour": "$created_at" ,
"interval":
"$subtract": [
"$minute": "$created_at" ,
"$mod": [ "$minute": "$created_at", 15]
]
,
"count": "$sum": 1
}
])
The second way is by using a little trick of when a date object is subtracted (or other direct math operation) from another date object, then the result is a numeric value representing the epoch timestamp milliseconds between the two objects. So just using the epoch date you get the epoch milliseconds representation. Then use date math for the interval:
db.collection.aggregate([
"$group":
"_id":
"$subtract": [
"$subtract": [ "$created_at", new Date("1970-01-01") ] ,
"$mod": [
"$subtract": [ "$created_at", new Date("1970-01-01") ] ,
1000 * 60 * 15
]
]
,
"count": "$sum": 1
])
So it depends on what kind of output format you want for the grouping interval. Both basically represent the same thing and have sufficient data to re-construct as a "date" object in your code.
You can put anything else you want in the "grouping operator" portion after the grouping _id
. I'm just using the basic "count" example in lieu of any real statement from yourself as to what you really want to do.
MongoDB 4.x and Upwards
There were some additions to Date Aggregation Operators since the original writing, but from MongoDB 4.0 there will be actual "real casting of types" as opposed to the basic math tricks done here with BSON Date conversion.
For instance we can use $toLong
and $toDate
as new helpers here:
db.collection.aggregate([
"$group":
"_id":
"$toDate":
"$subtract": [
"$toLong": "$created_at" ,
"$mod": [ "$toLong": "$created_at" , 1000 * 60 * 15 ]
]
,
"count": "$sum": 1
])
That's a bit shorter and does not require defining an external BSON Date for the "epoch" value as a constant in defining the pipeline so it's pretty consistent for all language implementations.
Those are just two of the "helper" methods for type conversion which all tie back to the $convert
method, which is a "longer" form of the implementation allowing for custom handling on null
or error in conversion.
It's even possible with such casting to get the Date
information from the ObjectId
of the primary key, as this would be a reliable source of "creation" date:
db.collection.aggregate([
"$group":
"_id":
"$toDate":
"$subtract": [
"$toLong": "$toDate": "$_id" ,
"$mod": [ "$toLong": "$toDate": "$_id" , 1000 * 60 * 15 ]
]
,
"count": "$sum": 1
])
So "casting types" with this sort of conversion can be pretty powerful tool.
Warning -
ObjectId
values are limited to precision to the second only for the internal time value that makes up part of their data allowing the$toDate
conversion. The actual inserted "time" is most probably dependent on the driver in use. Where precision is required, it's still recommended to use a discrete BSON Date field instead of relying onObjectId
values.
edited Apr 24 at 23:49
answered Nov 8 '14 at 6:31
Neil LunnNeil Lunn
107k24 gold badges199 silver badges200 bronze badges
107k24 gold badges199 silver badges200 bronze badges
9
too bad i can't accept for him - really useful answer !
– Petrov
Mar 28 '15 at 19:44
2
i couldn't agree more @Petrov
– aiapatag
Aug 27 '15 at 10:24
2
Thanks for providing these good solutions! I think there might be a small error in your first example. You are missing the grouping by hour (in order to retrieve the 15 minutes intereval – which I assume – should be by the hour). So you would need to add"hour": "$hour": "$created_at" ,
after thedayOfYear
-line
– skofgar
Jul 19 '17 at 23:25
Mongodb 4.0 has released in 2018 and you know these aggregations from 2014... How ???
– Ashh
Jul 20 '18 at 17:25
1
@AnthonyWinzlet, he edited his answer on 26 Apr 2018.
– Paul
Aug 25 '18 at 14:20
add a comment
|
9
too bad i can't accept for him - really useful answer !
– Petrov
Mar 28 '15 at 19:44
2
i couldn't agree more @Petrov
– aiapatag
Aug 27 '15 at 10:24
2
Thanks for providing these good solutions! I think there might be a small error in your first example. You are missing the grouping by hour (in order to retrieve the 15 minutes intereval – which I assume – should be by the hour). So you would need to add"hour": "$hour": "$created_at" ,
after thedayOfYear
-line
– skofgar
Jul 19 '17 at 23:25
Mongodb 4.0 has released in 2018 and you know these aggregations from 2014... How ???
– Ashh
Jul 20 '18 at 17:25
1
@AnthonyWinzlet, he edited his answer on 26 Apr 2018.
– Paul
Aug 25 '18 at 14:20
9
9
too bad i can't accept for him - really useful answer !
– Petrov
Mar 28 '15 at 19:44
too bad i can't accept for him - really useful answer !
– Petrov
Mar 28 '15 at 19:44
2
2
i couldn't agree more @Petrov
– aiapatag
Aug 27 '15 at 10:24
i couldn't agree more @Petrov
– aiapatag
Aug 27 '15 at 10:24
2
2
Thanks for providing these good solutions! I think there might be a small error in your first example. You are missing the grouping by hour (in order to retrieve the 15 minutes intereval – which I assume – should be by the hour). So you would need to add
"hour": "$hour": "$created_at" ,
after the dayOfYear
-line– skofgar
Jul 19 '17 at 23:25
Thanks for providing these good solutions! I think there might be a small error in your first example. You are missing the grouping by hour (in order to retrieve the 15 minutes intereval – which I assume – should be by the hour). So you would need to add
"hour": "$hour": "$created_at" ,
after the dayOfYear
-line– skofgar
Jul 19 '17 at 23:25
Mongodb 4.0 has released in 2018 and you know these aggregations from 2014... How ???
– Ashh
Jul 20 '18 at 17:25
Mongodb 4.0 has released in 2018 and you know these aggregations from 2014... How ???
– Ashh
Jul 20 '18 at 17:25
1
1
@AnthonyWinzlet, he edited his answer on 26 Apr 2018.
– Paul
Aug 25 '18 at 14:20
@AnthonyWinzlet, he edited his answer on 26 Apr 2018.
– Paul
Aug 25 '18 at 14:20
add a comment
|
I like the other answer here, and mostly for the use of date math instead of aggregation date operators which while helpful can also be a little obscure.
The only thing I want to add here is that you can also return a Date
object from the aggregation framework by this approach as opposed to the "numeric" timestamp as the result. It's just a little extra math on the same principles, using $add
:
db.collection.aggregate([
"$group":
"_id":
"$add": [
"$subtract": [
"$subtract": [ "$current_date", new Date(0) ] ,
"$mod": [
"$subtract": [ "$current_date", new Date(0) ] ,
1000 * 60 * 15
]
] ,
new Date(0)
]
,
"count": "$sum": 1
])
The Date(0)
contructs in JavaScript here represent the same "epoch" date in a shorter form, as 0 millisecond from epoch is epoch. But the main point is that when the "addition" to another BSON date object is done with a numeric identifier, then the inverse of the described condition is true and the end result is actually now a Date
.
All drivers will return the native Date
type to their language by this approach.
add a comment
|
I like the other answer here, and mostly for the use of date math instead of aggregation date operators which while helpful can also be a little obscure.
The only thing I want to add here is that you can also return a Date
object from the aggregation framework by this approach as opposed to the "numeric" timestamp as the result. It's just a little extra math on the same principles, using $add
:
db.collection.aggregate([
"$group":
"_id":
"$add": [
"$subtract": [
"$subtract": [ "$current_date", new Date(0) ] ,
"$mod": [
"$subtract": [ "$current_date", new Date(0) ] ,
1000 * 60 * 15
]
] ,
new Date(0)
]
,
"count": "$sum": 1
])
The Date(0)
contructs in JavaScript here represent the same "epoch" date in a shorter form, as 0 millisecond from epoch is epoch. But the main point is that when the "addition" to another BSON date object is done with a numeric identifier, then the inverse of the described condition is true and the end result is actually now a Date
.
All drivers will return the native Date
type to their language by this approach.
add a comment
|
I like the other answer here, and mostly for the use of date math instead of aggregation date operators which while helpful can also be a little obscure.
The only thing I want to add here is that you can also return a Date
object from the aggregation framework by this approach as opposed to the "numeric" timestamp as the result. It's just a little extra math on the same principles, using $add
:
db.collection.aggregate([
"$group":
"_id":
"$add": [
"$subtract": [
"$subtract": [ "$current_date", new Date(0) ] ,
"$mod": [
"$subtract": [ "$current_date", new Date(0) ] ,
1000 * 60 * 15
]
] ,
new Date(0)
]
,
"count": "$sum": 1
])
The Date(0)
contructs in JavaScript here represent the same "epoch" date in a shorter form, as 0 millisecond from epoch is epoch. But the main point is that when the "addition" to another BSON date object is done with a numeric identifier, then the inverse of the described condition is true and the end result is actually now a Date
.
All drivers will return the native Date
type to their language by this approach.
I like the other answer here, and mostly for the use of date math instead of aggregation date operators which while helpful can also be a little obscure.
The only thing I want to add here is that you can also return a Date
object from the aggregation framework by this approach as opposed to the "numeric" timestamp as the result. It's just a little extra math on the same principles, using $add
:
db.collection.aggregate([
"$group":
"_id":
"$add": [
"$subtract": [
"$subtract": [ "$current_date", new Date(0) ] ,
"$mod": [
"$subtract": [ "$current_date", new Date(0) ] ,
1000 * 60 * 15
]
] ,
new Date(0)
]
,
"count": "$sum": 1
])
The Date(0)
contructs in JavaScript here represent the same "epoch" date in a shorter form, as 0 millisecond from epoch is epoch. But the main point is that when the "addition" to another BSON date object is done with a numeric identifier, then the inverse of the described condition is true and the end result is actually now a Date
.
All drivers will return the native Date
type to their language by this approach.
edited Dec 29 '15 at 0:46
answered Aug 21 '15 at 9:42
Blakes SevenBlakes Seven
37k10 gold badges73 silver badges82 bronze badges
37k10 gold badges73 silver badges82 bronze badges
add a comment
|
add a comment
|
A little more beautiful for mongo db.version() < 3.0
db.collection.aggregate([
$match: created_at:$exists:1,
$group:
_id: $add:[
$dayOfYear: "$created_at" ,
$multiply: [$year: "$created_at", 1000]
],
count: $sum: 1
,
$sort:_id:-1
])
add a comment
|
A little more beautiful for mongo db.version() < 3.0
db.collection.aggregate([
$match: created_at:$exists:1,
$group:
_id: $add:[
$dayOfYear: "$created_at" ,
$multiply: [$year: "$created_at", 1000]
],
count: $sum: 1
,
$sort:_id:-1
])
add a comment
|
A little more beautiful for mongo db.version() < 3.0
db.collection.aggregate([
$match: created_at:$exists:1,
$group:
_id: $add:[
$dayOfYear: "$created_at" ,
$multiply: [$year: "$created_at", 1000]
],
count: $sum: 1
,
$sort:_id:-1
])
A little more beautiful for mongo db.version() < 3.0
db.collection.aggregate([
$match: created_at:$exists:1,
$group:
_id: $add:[
$dayOfYear: "$created_at" ,
$multiply: [$year: "$created_at", 1000]
],
count: $sum: 1
,
$sort:_id:-1
])
answered Sep 16 '15 at 10:58
StierlitzStierlitz
711 silver badge2 bronze badges
711 silver badge2 bronze badges
add a comment
|
add a comment
|
Another useful way:
db.collection.aggregate([
$group:
_id:
overallTime:
$dateToString: format: "%Y-%m-%dT%H", date: "$created_at"
,
interval: $trunc: $divide: [ $minute: "$created_at" , 15 ]
,
,
])
And more easier for min, hour, day intervals:
var format = "%Y-%m-%dT%H:%M"; // 1 min
var format = "%Y-%m-%dT%H"; // 1 hour
var format = "%Y-%m-%d"; // 1 day
db.collection.aggregate([
$group:
_id: $dateToString: format: format, date: "$created_at" ,
,
])
add a comment
|
Another useful way:
db.collection.aggregate([
$group:
_id:
overallTime:
$dateToString: format: "%Y-%m-%dT%H", date: "$created_at"
,
interval: $trunc: $divide: [ $minute: "$created_at" , 15 ]
,
,
])
And more easier for min, hour, day intervals:
var format = "%Y-%m-%dT%H:%M"; // 1 min
var format = "%Y-%m-%dT%H"; // 1 hour
var format = "%Y-%m-%d"; // 1 day
db.collection.aggregate([
$group:
_id: $dateToString: format: format, date: "$created_at" ,
,
])
add a comment
|
Another useful way:
db.collection.aggregate([
$group:
_id:
overallTime:
$dateToString: format: "%Y-%m-%dT%H", date: "$created_at"
,
interval: $trunc: $divide: [ $minute: "$created_at" , 15 ]
,
,
])
And more easier for min, hour, day intervals:
var format = "%Y-%m-%dT%H:%M"; // 1 min
var format = "%Y-%m-%dT%H"; // 1 hour
var format = "%Y-%m-%d"; // 1 day
db.collection.aggregate([
$group:
_id: $dateToString: format: format, date: "$created_at" ,
,
])
Another useful way:
db.collection.aggregate([
$group:
_id:
overallTime:
$dateToString: format: "%Y-%m-%dT%H", date: "$created_at"
,
interval: $trunc: $divide: [ $minute: "$created_at" , 15 ]
,
,
])
And more easier for min, hour, day intervals:
var format = "%Y-%m-%dT%H:%M"; // 1 min
var format = "%Y-%m-%dT%H"; // 1 hour
var format = "%Y-%m-%d"; // 1 day
db.collection.aggregate([
$group:
_id: $dateToString: format: format, date: "$created_at" ,
,
])
edited Oct 21 '17 at 4:12
answered Oct 20 '17 at 23:07
Sergey ReutskiySergey Reutskiy
2,1032 gold badges11 silver badges12 bronze badges
2,1032 gold badges11 silver badges12 bronze badges
add a comment
|
add a comment
|
@Neil Lunn's answer at https://stackoverflow.com/a/26814496/8474325 for MongoDb 4.x upwards is fantastic. But there is a small mistake in the code where he uses ObjectId for the aggregation. The Line "$toDate": "_id"
has to be changed to "$toDate": "$_id"
for the code to work.
Here's the corrected code.
db.collection.aggregate([
"$group":
"_id":
"$toDate":
"$subtract": [
"$toLong": "$toDate": "$_id" ,
"$mod": [ "$toLong": "$toDate": "$_id" , 1000 * 60 * 15 ]
]
,
"count": "$sum": 1
])
add a comment
|
@Neil Lunn's answer at https://stackoverflow.com/a/26814496/8474325 for MongoDb 4.x upwards is fantastic. But there is a small mistake in the code where he uses ObjectId for the aggregation. The Line "$toDate": "_id"
has to be changed to "$toDate": "$_id"
for the code to work.
Here's the corrected code.
db.collection.aggregate([
"$group":
"_id":
"$toDate":
"$subtract": [
"$toLong": "$toDate": "$_id" ,
"$mod": [ "$toLong": "$toDate": "$_id" , 1000 * 60 * 15 ]
]
,
"count": "$sum": 1
])
add a comment
|
@Neil Lunn's answer at https://stackoverflow.com/a/26814496/8474325 for MongoDb 4.x upwards is fantastic. But there is a small mistake in the code where he uses ObjectId for the aggregation. The Line "$toDate": "_id"
has to be changed to "$toDate": "$_id"
for the code to work.
Here's the corrected code.
db.collection.aggregate([
"$group":
"_id":
"$toDate":
"$subtract": [
"$toLong": "$toDate": "$_id" ,
"$mod": [ "$toLong": "$toDate": "$_id" , 1000 * 60 * 15 ]
]
,
"count": "$sum": 1
])
@Neil Lunn's answer at https://stackoverflow.com/a/26814496/8474325 for MongoDb 4.x upwards is fantastic. But there is a small mistake in the code where he uses ObjectId for the aggregation. The Line "$toDate": "_id"
has to be changed to "$toDate": "$_id"
for the code to work.
Here's the corrected code.
db.collection.aggregate([
"$group":
"_id":
"$toDate":
"$subtract": [
"$toLong": "$toDate": "$_id" ,
"$mod": [ "$toLong": "$toDate": "$_id" , 1000 * 60 * 15 ]
]
,
"count": "$sum": 1
])
answered Jan 4 at 5:47
sanair96sanair96
111 silver badge4 bronze badges
111 silver badge4 bronze badges
add a comment
|
add a comment
|
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f26814427%2fgroup-result-by-15-minutes-time-interval-in-mongodb%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
12
Is their something in the provided answer that is unclear or does not apply to your situation? Noting that it is still not accepted.
– Neil Lunn
Nov 13 '14 at 7:54
3
Don't bother, he already took answer, why bother yourself with accepting answers.
– nurgasemetey
Aug 26 '16 at 21:07