title: MongoDB Time Series Aggregation
body: <p>I'm reading sensor data at configurable intervals, but for this example let's say every 30 seconds. I want to be able to group the data by hour, day, week, month and year intervals. I also want to be able to aggregate averages over a group of sensors for the same intervals. </p>
  
  <p><strong>Example Use Cases:</strong></p>
  
  <p><em>1. Get the last 4 month totals for sensor id: x</em></p>
  
  <p><em>2. Get the last 4 month average totals for sensors with group_id: y</em></p>
  
  <p>Use Case 2 Clarified</p>
  
  <p>The following all have the same group_id</p>
  
  <pre><code>sensor_id | month 1 | month 2 | month 3 | month 4
       1    |   10    |   15    |   5     |    10
       2    |   20    |   30    |   30    |    5
       3    |   5     |   20    |   40    |    20
  </code></pre>
  
  <p>Output</p>
  
  <pre><code>month1 : 11.67, month2: 21.67, month3: 25, month4: 11.67
  </code></pre>
  
  <p>I have seen lots of approaches to storing time-series data in MongoDB. I'm thinking of having a collection for each interval, including the raw time values and having each document expire after a certain time period. </p>
  
  <p>MonthPoint example document</p>
  
  <pre><code>{
      "_id": {
          "$oid": "55270059a791051d4a4e0e41"
      },
      "sensor_id": "1",
      "group_id" : "4",
      "timestamp": {
          "$date": "2015-04-01T00:00:00.000Z"
      },
      "sum": 40
      "count": 200
  }
  </code></pre>
  
  <p>For each point that comes in I would have to perform a write to each collection, but reading the data would be quick. </p>
  
  <p>Use Case 1, would be a very simple query:</p>
  
  <pre><code>MonthPoints.find({
      sensor_id : x,
      timestamp : {
          $gte: startDate,
          $lt: currentDate
      }
  });
  </code></pre>
  
  <p>But how would I aggregate for Use Case 2? Is it possible to achieve this in one aggregation? I see how it could be achieved using 4 separate aggregations, getting the average for each month across a group_id.</p>