2
votes

I am trying to aggregate using time buckets. Then, I want to return an array full of the values per day (0 when no document found). The aggeagate function work wondefully, but when I replace the callback (formerly console.log) like this:

Star.aggregate([{
    $match: {
      "mod": new mongoose.Types.ObjectId("53765a122c0cda28199df3f4"),
      "time_bucket.month": new TimeBucket().month
    }
    },
  {
    $group: {
      _id: "$time_bucket.day",
      stars: {
        "$sum": 1
      }
    }

      },
  {
    $sort: {
      '_id': 1
    }
      }],
function (err, mods) {
  console.log(err, mods);
  mods = mods.map(function (model) {
    return model.toObject ? model.toObject() : model
  });
  var i, time, docs = [];
  var hasGap = function (a, b) {
    a = a.replace(/-/g, '');
    b = b.replace(/-/g, '');
    return a - b !== 1
  }

  var process = function (i, mods, docs) {
    if (hasGap(mods[i]._id, mods[i + 1]._id)) {
      docs.push(0);
      return process(i, mods, docs)
    }
    docs.push(mods[i].stars);
    return process(i + 1, mods, docs)

  };
  process(0, mods, docs);
  console.log(docs);
});

I get:

C:\Users\Me\Nodejs\node_modules\mongoose\node_modules\mongodb\lib\mongodb\connection\base.js:245
        throw message;
              ^
RangeError: Maximum call stack size exceeded
1

1 Answers

2
votes

Your process function is recursive and has no path that breaks the recursion by not calling process again. A classic infinite recursion stack overflow.

The solution is to change the process function so that it checks for being at the end of the mods array of result docs and then simply return at that point instead of calling itself again.

So a check like:

if (i >= mods.length) return;