title: Using Mongoose Aggregation to Group By and Calculate Averages
body: <p>I have a MongoDB collection with the following structure:</p>
  
  <pre><code>    Prices: [ 
          exchange, symbol, volume, buy, sell, last, low, high
      ]
  </code></pre>
  
  <p>I am using Mongoose to query the records, and I'd like to get averages of buy, sell, last, low, high over the last 3 hours grouped by the symbol.</p>
  
  <p>Essentially my goal is to display something like the following:
          (Let A, B, C, D, E, F be placeholders for numbers)</p>
  
  <pre><code>    Latest Prices for Exchange:
          Symbol A    Volume: A   Buy: B  Sell: C Last: D Low: E  High: F Spread: C - B
          Symbol B    Volume: A   Buy: B  Sell: C Last: D Low: E  High: F Spread: C - B
  
      3 Hour Averages for Exchange:
          Symbol A:   Volume: A   Buy: B  Sell: C Last: D Low: E  High: F Spread: C - B
          Symbol B:   Volume: X   Buy: B  Sell: C Last: D Low: E  High: F Spread: C - B
  </code></pre>
  
  <p>I've been reading through the MongoDB docs: 
  <a href="https://docs.mongodb.org/manual/reference/operator/aggregation/group/" rel="nofollow">https://docs.mongodb.org/manual/reference/operator/aggregation/group/</a></p>
  
  <p>To get the averages I've tried something like this:  </p>
  
  <pre><code>    query = Prices.aggregate([
          {
              $group: {
                  _id: "$symbol",
                  avg_last: { $avg: "$last" },
                  avg_buy: { $avg: "$buy" },
                  avg_sell: { $avg: "$sell" },
                  avg_low: { $avg: "$low" },
                  avg_high: { $avg: "$high" },
                  averageSpread: { $avg: { $subtract: ["$sell", "$buy"] } },
                  count: { $sum: 1 }
              }
          }
      ]);
  </code></pre>
  
  <p>The problem is that there is no "condition" in this to limit the results to the past 3 hours.</p>
  
  <p>Using the MongoDB Docs again for $cond 
  <a href="https://docs.mongodb.org/manual/reference/operator/aggregation/cond/" rel="nofollow">https://docs.mongodb.org/manual/reference/operator/aggregation/cond/</a></p>
  
  <p>I've tried to apply this:</p>
  
  <pre><code>    var threeHoursAgo = new Date();
      threeHoursAgo.setHours(threeHoursAgo.getHours() - 3);
  
      query = Prices.aggregate([
          {
              $group: {
                  _id: "$symbol",
                  avg_last: { $avg: "$last" },
                  avg_buy: { $avg: "$buy" },
                  avg_sell: { $avg: "$sell" },
                  avg_low: { $avg: "$low" },
                  avg_high: { $avg: "$high" },
                  averageSpread: { $avg: { $subtract: ["$sell", "$buy"] } },
                  count: { $sum: 1 }
              },
              $cond: {
                  exchange: strategy.primaryExchanges[i].exchange._id,
                  timestamp: {
                      $gte: threeHoursAgo
                  }
              }
          }
      ]);
  </code></pre>
  
  <p>But I'm getting the following error:</p>
  
  <pre><code>"Error: Arguments must be aggregate pipline operators".
  </code></pre>
  
  <p><strong>EDIT:</strong> I've also tried using $match like:</p>
  
  <pre><code>    query = Prices.aggregate([
          {
              $group: {
                  _id: "$symbol",
                  avg_last: { $avg: "$last" },
                  avg_buy: { $avg: "$buy" },
                  avg_sell: { $avg: "$sell" },
                  avg_low: { $avg: "$low" },
                  avg_high: { $avg: "$high" },
                  averageSpread: { $avg: { $subtract: ["$sell", "$buy"] } },
                  count: { $sum: 1 }
              }
          },
          {
              $match: {
                  $and: [
                      {exchange: strategy.primaryExchanges[i].exchange._id},
                      {timestamp: {$gte: threeHoursAgo} }
                  ]
              }
          }
      ]);
  </code></pre>
  
  <p>but I get an empty array back.</p>
  
  <p><strong>EDIT 2</strong>
  Here is a sample document from my Prices collection:</p>
  
  <pre><code> {"_id":"ObjectId(56296ac0603c75c80b3d581f)","symbol":"XBT24H","contract":"XBT24H","exchange":"ObjectId(55dc8ae9ecb73538125ddd9a)","timestamp":"ISODate(2015-10-22T23:01:15.000Z)","volume":260475,"buy":275.41,"sell":275.7,"low":274.44,"last":275.7,"high":277.03,"__v":0}
  </code></pre>