title: Avoiding exceeding call stack size in Node.JS with Mongoose
body: <p>I'm relatively new to Node, so please do point any and all errors you see out.</p>
  
  <p>I'm trying to write a relatively simple application; take JSON string of ~1k objects, split them up into groups and calculate a total of a specifical value in each object for that group. Problem is, I need the total to be precise down to quite a few decimals, and as such, I'm using BigDecimal (which I believe is what causes the many calls). </p>
  
  <p>I get the following error:</p>
  
  <pre><code>RangeError: Maximum call stack size exceeded
  </code></pre>
  
  <p>I understand that this error comes from a function calling a function, so on and so forth, until the chain has become long enough to likely be an infinite loop. However, this also seems to be triggered by my function below.</p>
  
  <p>I'm honestly stomped, and not quite sure how to work around this. With a callback-based application such as Node, you'd think there was well established standards for how to work around the call stack size. Unfortunately, my searching has found nothing. Any help would be greatly appreciated.</p>
  
  <p>Code is as follows:</p>
  
  <pre><code>// Mongoose
  mongoose.connect("mongodb://localhost/test");
  var db = mongoose.connection;
  db.on("error", console.error.bind(console, "connection error:"));
  
  // If connection success
  db.once("open", function() {
      // Define current period schema/model
      var Mixed = mongoose.Schema.Types.Mixed;
      var curSchema = mongoose.Schema({
          total: Mixed,
          startTime: { type: Number, default: 0 },
          lastTime: { type: Number, default: 0 },
          high: Mixed,
          low: Mixed 
      });
      var curModel = mongoose.model("curModel", curSchema);
      // Create current period
      currentPeriod = new curModel({total: new bigdecimal.BigDecimal("0"),
                                          high: new bigdecimal.BigDecimal("0"),
                                          low: new bigdecimal.BigDecimal("999") });
  
      curModel.find(function(err,current) {
              if (err) console.error("=== FAILED TO FIND CURRENT PERIOD! ===");
              console.log(current);
          });
  
      scraper.retrieve("[url-of-json]",{},
      updateOrders);
  });
  
  /* *
   * Update database with newest orders
   */
  var updateOrders = function(error, r, body) {
      var response = JSON.parse(body);
  
      // Stop if retrieval failed
      if (error || !response || response.error) {
          console.log("Failed to retreive trade history:");
          console.log(error || response.error);
          return;
      }
      // Loop through every order, from bottom
      var k = Object.keys(response);
      for (var i = k.length - 1; i&gt;=0; i--) {
          var j = k[i];
          var amount = new bigdecimal.BigDecimal(response[j].amount);
          var price = new bigdecimal.BigDecimal(response[j].price);
  
          // If we haven't logged this order yet (and it's in the current period)
          if (response[j].date &gt;= currentPeriod.lastTime &amp;&amp; response[j].date - currentPeriod.startTime &lt; 900) {
  
              if (!(i%20)) console.log("Adding " + amount.toString() + " to total. Time: " + (response[j].date - currentPeriod.startTime) + ". I: " + i);
              currentPeriod.total = currentPeriod.total.add(amount);
              currentPeriod.lastTime = response[j].date;
              if (price.compareTo(currentPeriod.high)===1) currentPeriod.high = price;
              if (price.compareTo(currentPeriod.low)===-1) currentPeriod.low = price;
          }
  
          // If we've passed the 15-minute mark
          if (response[j].date - currentPeriod.startTime &gt;= 900) {
              // If we should save
              if (currentPeriod.startTime !== 0) {
                  console.log("=== Period end ("+response[j].date+") === ");
                  console.log("End index: " + i);
                  console.log("Total: " + currentPeriod.total.toString());
                  console.log("High: " + currentPeriod.high.toString());
                  console.log("Low: " + currentPeriod.low.toString());
                  console.log("Closing: " + price);
  
                  // Mark as modified
                  currentPeriod.markModified("total");currentPeriod.markModified("lastTime");
                  currentPeriod.markModified("startTime");currentPeriod.markModified("high");
                  currentPeriod.markModified("low");
                  // Save
                  currentPeriod.save(function(err,period) {
                          if (err) console.error("=== Failed to save current period! ===");
                      });
              }
  
              currentPeriod.total = new bigdecimal.BigDecimal("0").add(amount);
              currentPeriod.lastTime = response[j].date;
              currentPeriod.startTime = response[j].date;
              currentPeriod.high = price;
              currentPeriod.low = price;
          }
      }
  }
  </code></pre>