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;








40















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.










share|improve this question





















  • 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

















40















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.










share|improve this question





















  • 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













40












40








40


25






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.










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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












  • 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












5 Answers
5






active

oldest

votes


















105


















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 on ObjectId values.







share|improve this answer






















  • 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 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






  • 1





    @AnthonyWinzlet, he edited his answer on 26 Apr 2018.

    – Paul
    Aug 25 '18 at 14:20


















15


















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.






share|improve this answer


































    7
















    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
    ])





    share|improve this answer
































      4
















      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" ,
      ,
      ])





      share|improve this answer


































        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

        ])





        share|improve this answer



























          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
          );



          );














          draft saved

          draft discarded
















          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









          105


















          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 on ObjectId values.







          share|improve this answer






















          • 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 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






          • 1





            @AnthonyWinzlet, he edited his answer on 26 Apr 2018.

            – Paul
            Aug 25 '18 at 14:20















          105


















          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 on ObjectId values.







          share|improve this answer






















          • 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 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






          • 1





            @AnthonyWinzlet, he edited his answer on 26 Apr 2018.

            – Paul
            Aug 25 '18 at 14:20













          105














          105










          105











          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 on ObjectId values.







          share|improve this answer

















          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 on ObjectId values.








          share|improve this answer














          share|improve this answer



          share|improve this answer








          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 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






          • 1





            @AnthonyWinzlet, he edited his answer on 26 Apr 2018.

            – Paul
            Aug 25 '18 at 14:20












          • 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 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






          • 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













          15


















          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.






          share|improve this answer































            15


















            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.






            share|improve this answer





























              15














              15










              15











              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.






              share|improve this answer

















              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.







              share|improve this answer














              share|improve this answer



              share|improve this answer








              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
























                  7
















                  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
                  ])





                  share|improve this answer





























                    7
















                    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
                    ])





                    share|improve this answer



























                      7














                      7










                      7









                      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
                      ])





                      share|improve this answer













                      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
                      ])






                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered Sep 16 '15 at 10:58









                      StierlitzStierlitz

                      711 silver badge2 bronze badges




                      711 silver badge2 bronze badges
























                          4
















                          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" ,
                          ,
                          ])





                          share|improve this answer































                            4
















                            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" ,
                            ,
                            ])





                            share|improve this answer





























                              4














                              4










                              4









                              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" ,
                              ,
                              ])





                              share|improve this answer















                              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" ,
                              ,
                              ])






                              share|improve this answer














                              share|improve this answer



                              share|improve this answer








                              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
























                                  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

                                  ])





                                  share|improve this answer





























                                    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

                                    ])





                                    share|improve this answer



























                                      1














                                      1










                                      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

                                      ])





                                      share|improve this answer













                                      @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

                                      ])






                                      share|improve this answer












                                      share|improve this answer



                                      share|improve this answer










                                      answered Jan 4 at 5:47









                                      sanair96sanair96

                                      111 silver badge4 bronze badges




                                      111 silver badge4 bronze badges































                                          draft saved

                                          draft discarded















































                                          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.




                                          draft saved


                                          draft discarded














                                          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





















































                                          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







                                          Popular posts from this blog

                                          Kamusi Yaliyomo Aina za kamusi | Muundo wa kamusi | Faida za kamusi | Dhima ya picha katika kamusi | Marejeo | Tazama pia | Viungo vya nje | UrambazajiKuhusu kamusiGo-SwahiliWiki-KamusiKamusi ya Kiswahili na Kiingerezakuihariri na kuongeza habari

                                          Swift 4 - func physicsWorld not invoked on collision? The Next CEO of Stack OverflowHow to call Objective-C code from Swift#ifdef replacement in the Swift language@selector() in Swift?#pragma mark in Swift?Swift for loop: for index, element in array?dispatch_after - GCD in Swift?Swift Beta performance: sorting arraysSplit a String into an array in Swift?The use of Swift 3 @objc inference in Swift 4 mode is deprecated?How to optimize UITableViewCell, because my UITableView lags

                                          Access current req object everywhere in Node.js ExpressWhy are global variables considered bad practice? (node.js)Using req & res across functionsHow do I get the path to the current script with Node.js?What is Node.js' Connect, Express and “middleware”?Node.js w/ express error handling in callbackHow to access the GET parameters after “?” in Express?Modify Node.js req object parametersAccess “app” variable inside of ExpressJS/ConnectJS middleware?Node.js Express app - request objectAngular Http Module considered middleware?Session variables in ExpressJSAdd properties to the req object in expressjs with Typescript