0

Hi I am new to node and I am trying to run a mongoose query with multiple queries in one request and I've run into a problem that just doesn't make sense. I am retrieving energy history data stored in mongodb for the previous 7 days. I comment out from day 4 to 7 the request works, but with the code from day 4 - 7 uncommented I am thrown this error:

story.kwhsNow[0].fromgrid - data[0].fromgrid - history.kwhsDayAgo[0].fromgrid 
                                                                ^TypeError: Cannot read property 'fromgrid' of undefined

This occurs after the fourDaysAgo query.

Here is the code in the request:

httpsRouter.get('/api/weekhistory', function(req, res) {

  var history = {kwhsNow: '', kwhsToday: '', kwhsDayAgo: '', kwhsTwoDaysAgo: '', kwhsThreeDaysAgo: '', kwhsFourDaysAgo: '', kwhsFiveDaysAgo: '', kwhsSixDaysAgo: '', kwhsSevenDaysAgo: ''};

      kwhsNowQuery = eagleData.eagleKwhs.find(),
      kwhsNowQuery.sort('-_id');
      kwhsNowQuery.limit(1);
      kwhsNowQuery.exec(function(err, data) {
        // if there is an error retrieving, send the error. nothing after res.send(err) will execute
        if (err)
            res.send(err)

        history.kwhsNow = data;
    });       

  var sinceToday = moment().hours(0).minutes(0).seconds(0).format('x');

  var sinceTodayQuery = eagleData.eagleKwhs.find();
      sinceTodayQuery.where('_id').gte(sinceToday - 10000).lte(sinceToday + 10000); 
      sinceTodayQuery.limit(1);
      sinceTodayQuery.exec(function(err, data) {
        // if there is an error retrieving, send the error. nothing after res.send(err) will execute
        if (err)
            res.send(err)
        console.log('Since today: ',data[0].fromgrid);  
        data[0].fromgrid = history.kwhsNow[0].fromgrid - data[0].fromgrid;  
        history.kwhsToday = data;

    });

  var dayAgo = moment().subtract(1, 'days').hours(0).minutes(0).seconds(0).format('x');

  var dayAgoQuery = eagleData.eagleKwhs.find();
      dayAgoQuery.where('_id').gte(dayAgo - 10000).lte(dayAgo + 10000); 
      dayAgoQuery.limit(1);
      dayAgoQuery.exec(function(err, data) {
        // if there is an error retrieving, send the error. nothing after res.send(err) will execute
        if (err)
            res.send(err)
        console.log('Day Ago: ',data[0].fromgrid);    
        data[0].fromgrid = history.kwhsNow[0].fromgrid - data[0].fromgrid - history.kwhsToday[0].fromgrid;  
        history.kwhsDayAgo = data;
        res.json(history); 
        console.log(history);// return all in JSON format       
    });         

  var twoDaysAgo = moment().subtract(2, 'days').hours(0).minutes(0).seconds(0).format('x');

  var twoDaysAgoQuery = eagleData.eagleKwhs.find();
      twoDaysAgoQuery.where('_id').gte(twoDaysAgo - 10000).lte(twoDaysAgo + 10000); 
      twoDaysAgoQuery.limit(1);
      twoDaysAgoQuery.exec(function(err, data) {
        // if there is an error retrieving, send the error. nothing after res.send(err) will execute
        if (err)
            res.send(err)

        console.log('Two Days Ago: ',data[0].fromgrid);    
        data[0].fromgrid = history.kwhsNow[0].fromgrid - data[0].fromgrid - history.kwhsToday[0].fromgrid - history.kwhsDayAgo[0].fromgrid;  
        history.kwhsTwoDaysAgo = data;

    });

  var threeDaysAgo = moment().subtract(3, 'days').hours(0).minutes(0).seconds(0).format('x');

  var threeDaysAgoQuery = eagleData.eagleKwhs.find();
      threeDaysAgoQuery.where('_id').gte(threeDaysAgo - 10000).lte(threeDaysAgo + 10000); 
      threeDaysAgoQuery.limit(1);
      threeDaysAgoQuery.exec(function(err, data) {
        // if there is an error retrieving, send the error. nothing after res.send(err) will execute
        if (err)
            res.send(err)

        console.log('Three Days Ago: ',data[0].fromgrid);    
        data[0].fromgrid = history.kwhsNow[0].fromgrid - data[0].fromgrid - history.kwhsToday[0].fromgrid - history.kwhsDayAgo[0].fromgrid - history.twoDaysAgo[0].fromgrid;  
        history.kwhsThreeDaysAgo = data;
    });


  var fourDaysAgo = moment().subtract(4, 'days').hours(0).minutes(0).seconds(0).format('x');    

  var fourDaysAgoQuery = eagleData.eagleKwhs.find();
      fourDaysAgoQuery.where('_id').gte(fourDaysAgo - 10000).lte(fourDaysAgo + 10000); 
      fourDaysAgoQuery.limit(1);
      fourDaysAgoQuery.exec(function(err, data) {
         //if there is an error retrieving, send the error. nothing after res.send(err) will execute
        if (err)
            res.send(err)

        console.log('Four Days Ago: ',data[0].fromgrid);                    //history.kwhsToday[0].fromgrid -
        data[0].fromgrid = history.kwhsNow[0].fromgrid - data[0].fromgrid - history.kwhsDayAgo[0].fromgrid - history.twoDaysAgo[0].fromgrid - history.threeDaysAgo[0].fromgrid;  
        history.kwhsFourDaysAgo = data;
    });

  var fiveDaysAgo = moment().subtract(5, 'days').hours(0).minutes(0).seconds(0).format('x');    

  var fiveDaysAgoQuery = eagleData.eagleKwhs.find();
      fiveDaysAgoQuery.where('_id').gte(fiveDaysAgo - 10000).lte(fiveDaysAgo + 10000); 
      fiveDaysAgoQuery.limit(1);
      fiveDaysAgoQuery.exec(function(err, data) {
        // if there is an error retrieving, send the error. nothing after res.send(err) will execute
        if (err)
            res.send(err)

        console.log('Five Days Ago: ',data[0].fromgrid);    
        data[0].fromgrid = history.kwhsNow[0].fromgrid - data[0].fromgrid - history.kwhsToday[0].fromgrid - history.kwhsDayAgo[0].fromgrid - history.twoDaysAgo[0].fromgrid - history.threeDaysAgo[0].fromgrid - history.fourDaysAgo[0].fromgrid;  
        history.kwhsFiveDaysAgo = data;
    });

 var sixDaysAgo = moment().subtract(6, 'days').hours(0).minutes(0).seconds(0).format('x');    

  var sixDaysAgoQuery = eagleData.eagleKwhs.find();
      sixDaysAgoQuery.where('_id').gte(sixDaysAgo - 10000).lte(sixDaysAgo + 10000); 
      sixDaysAgoQuery.limit(1);
      sixDaysAgoQuery.exec(function(err, data) {
        // if there is an error retrieving, send the error. nothing after res.send(err) will execute
        if (err)
            res.send(err)

        console.log('Six Days Ago: ',data[0].fromgrid);    
        data[0].fromgrid = history.kwhsNow[0].fromgrid - data[0].fromgrid - history.kwhsToday[0].fromgrid - history.kwhsDayAgo[0].fromgrid - history.twoDaysAgo[0].fromgrid - history.threeDaysAgo[0].fromgrid - history.fourDaysAgo[0].fromgrid - history.fiveDaysAgo[0].fromgrid;  
        history.kwhsSixDaysAgo = data;
    });

 var sevenDaysAgo = moment().subtract(7, 'days').hours(0).minutes(0).seconds(0).format('x');    

  var sevenDaysAgoQuery = eagleData.eagleKwhs.find();
      sevenDaysAgoQuery.where('_id').gte(sevenDaysAgo - 10000).lte(sevenDaysAgo + 10000); 
      sevenDaysAgoQuery.limit(1);
      sevenDaysAgoQuery.exec(function(err, data) {
        // if there is an error retrieving, send the error. nothing after res.send(err) will execute
        if (err)
            res.send(err)

        console.log('Seven Days Ago: ',data[0].fromgrid);    
        data[0].fromgrid = history.kwhsNow[0].fromgrid - data[0].fromgrid - history.kwhsToday[0].fromgrid - history.kwhsDayAgo[0].fromgrid - history.twoDaysAgo[0].fromgrid - history.threeDaysAgo[0].fromgrid - history.fourDaysAgo[0].fromgrid - history.fiveDaysAgo[0].fromgrid - history.sixDaysAgo[0].fromgrid;  
        history.kwhsSevenDaysAgo = data;
        res.json(history); 
        console.log(history);// return all in JSON format
    });

});

I do not understand why history.kwhsDayAgo[0].fromgrid on the fourDaysAgo query has not been set from the previous code and if not a mongoose error should have been sent back to the req. And as I already said the code works when day 4 -7 is commented out. I feel like there could be a more efficient way of achieving this but I am yet to find anyone who has posted a similar problem. I'd appreciate any help.

1
  • Make use of the Async module
    – ZeMoon
    Commented Apr 7, 2015 at 6:04

1 Answer 1

1

You should use the Async module to populate the history object.

Install the module

npm install async

First require the module in the file

var Async = require('async');

Then in the request handler:

var history = {

    kwhsNow: function (callback) {
        kwhsNowQuery = eagleData.eagleKwhs.find(),
          kwhsNowQuery.sort('-_id');
          kwhsNowQuery.limit(1);
          kwhsNowQuery.exec(function(err, data) {
            // if there is an error retrieving, send the error. nothing after res.send(err) will execute
            if (err)
                return callback(err)

            callback(null, data);
        });
    }, 

    kwhsToday: function (callback) {
        var sinceToday = moment().hours(0).minutes(0).seconds(0).format('x');

        var sinceTodayQuery = eagleData.eagleKwhs.find();
          sinceTodayQuery.where('_id').gte(sinceToday - 10000).lte(sinceToday + 10000); 
          sinceTodayQuery.limit(1);
          sinceTodayQuery.exec(function(err, data) {
            // if there is an error retrieving, send the error. nothing after res.send(err) will execute
            if (err)
                return callback(err);

            console.log('Since today: ',data[0].fromgrid);  
            data[0].fromgrid = history.kwhsNow[0].fromgrid - data[0].fromgrid;  
            callback (null, data);

        });
    }, 

    kwhsDayAgo: function (callback) {
        var dayAgo = moment().subtract(1, 'days').hours(0).minutes(0).seconds(0).format('x');

        var dayAgoQuery = eagleData.eagleKwhs.find();
          dayAgoQuery.where('_id').gte(dayAgo - 10000).lte(dayAgo + 10000); 
          dayAgoQuery.limit(1);
          dayAgoQuery.exec(function(err, data) {
            // if there is an error retrieving, send the error. nothing after res.send(err) will execute
            if (err)
                return callback(err);

            console.log('Day Ago: ',data[0].fromgrid);    
            data[0].fromgrid = history.kwhsNow[0].fromgrid - data[0].fromgrid - history.kwhsToday[0].fromgrid;  
            callback (null, data);
            res.json(history); 
            console.log(history);// return all in JSON format       
        }); 
    }, 

    kwhsTwoDaysAgo: function (callback) {
        var twoDaysAgo = moment().subtract(2, 'days').hours(0).minutes(0).seconds(0).format('x');

        var twoDaysAgoQuery = eagleData.eagleKwhs.find();
        twoDaysAgoQuery.where('_id').gte(twoDaysAgo - 10000).lte(twoDaysAgo + 10000); 
        twoDaysAgoQuery.limit(1);
        twoDaysAgoQuery.exec(function(err, data) {
        // if there is an error retrieving, send the error. nothing after res.send(err) will execute
            if (err)
                return callback(err);

            console.log('Two Days Ago: ',data[0].fromgrid);    
            data[0].fromgrid = history.kwhsNow[0].fromgrid - data[0].fromgrid - history.kwhsToday[0].fromgrid - history.kwhsDayAgo[0].fromgrid;  
            callback (null, data);

        });

    }, kwhsThreeDaysAgo: function (callback) {
            var threeDaysAgo = moment().subtract(3, 'days').hours(0).minutes(0).seconds(0).format('x');

          var threeDaysAgoQuery = eagleData.eagleKwhs.find();
          threeDaysAgoQuery.where('_id').gte(threeDaysAgo - 10000).lte(threeDaysAgo + 10000); 
          threeDaysAgoQuery.limit(1);
          threeDaysAgoQuery.exec(function(err, data) {
            // if there is an error retrieving, send the error. nothing after res.send(err) will execute
            if (err)
                return callback(err);

            console.log('Three Days Ago: ',data[0].fromgrid);    
            data[0].fromgrid = history.kwhsNow[0].fromgrid - data[0].fromgrid - history.kwhsToday[0].fromgrid - history.kwhsDayAgo[0].fromgrid - history.twoDaysAgo[0].fromgrid;  
            callback (null, data);
        });

    }, kwhsFourDaysAgo: function (callback) {
            var fourDaysAgo = moment().subtract(4, 'days').hours(0).minutes(0).seconds(0).format('x');    

          var fourDaysAgoQuery = eagleData.eagleKwhs.find();
          fourDaysAgoQuery.where('_id').gte(fourDaysAgo - 10000).lte(fourDaysAgo + 10000); 
          fourDaysAgoQuery.limit(1);
          fourDaysAgoQuery.exec(function(err, data) {
             //if there is an error retrieving, send the error. nothing after res.send(err) will execute
            if (err)
                return callback(err);

            console.log('Four Days Ago: ',data[0].fromgrid);                    //history.kwhsToday[0].fromgrid -
            data[0].fromgrid = history.kwhsNow[0].fromgrid - data[0].fromgrid - history.kwhsDayAgo[0].fromgrid - history.twoDaysAgo[0].fromgrid - history.threeDaysAgo[0].fromgrid;  
            callback (null, data);
        });
    }, kwhsFiveDaysAgo: function (callback) {
        var fiveDaysAgo = moment().subtract(5, 'days').hours(0).minutes(0).seconds(0).format('x');    

      var fiveDaysAgoQuery = eagleData.eagleKwhs.find();
          fiveDaysAgoQuery.where('_id').gte(fiveDaysAgo - 10000).lte(fiveDaysAgo + 10000); 
          fiveDaysAgoQuery.limit(1);
          fiveDaysAgoQuery.exec(function(err, data) {
            // if there is an error retrieving, send the error. nothing after res.send(err) will execute
            if (err)
                return callback(err);

            console.log('Five Days Ago: ',data[0].fromgrid);    
            data[0].fromgrid = history.kwhsNow[0].fromgrid - data[0].fromgrid - history.kwhsToday[0].fromgrid - history.kwhsDayAgo[0].fromgrid - history.twoDaysAgo[0].fromgrid - history.threeDaysAgo[0].fromgrid - history.fourDaysAgo[0].fromgrid;  
            callback (null, data);
        });
    }, 

    kwhsSixDaysAgo: function (callback) {

        var sixDaysAgo = moment().subtract(6, 'days').hours(0).minutes(0).seconds(0).format('x');    

      var sixDaysAgoQuery = eagleData.eagleKwhs.find();
          sixDaysAgoQuery.where('_id').gte(sixDaysAgo - 10000).lte(sixDaysAgo + 10000); 
          sixDaysAgoQuery.limit(1);
          sixDaysAgoQuery.exec(function(err, data) {
            // if there is an error retrieving, send the error. nothing after res.send(err) will execute
            if (err)
                return callback(err);

            console.log('Six Days Ago: ',data[0].fromgrid);    
            data[0].fromgrid = history.kwhsNow[0].fromgrid - data[0].fromgrid - history.kwhsToday[0].fromgrid - history.kwhsDayAgo[0].fromgrid - history.twoDaysAgo[0].fromgrid - history.threeDaysAgo[0].fromgrid - history.fourDaysAgo[0].fromgrid - history.fiveDaysAgo[0].fromgrid;  
            callback (null, data);
        });
    }, 

    kwhsSevenDaysAgo: function (callback){
        var sevenDaysAgo = moment().subtract(7, 'days').hours(0).minutes(0).seconds(0).format('x');    

      var sevenDaysAgoQuery = eagleData.eagleKwhs.find();
          sevenDaysAgoQuery.where('_id').gte(sevenDaysAgo - 10000).lte(sevenDaysAgo + 10000); 
          sevenDaysAgoQuery.limit(1);
          sevenDaysAgoQuery.exec(function(err, data) {
            // if there is an error retrieving, send the error. nothing after res.send(err) will execute
            if (err)
                return callback(err);

            console.log('Seven Days Ago: ',data[0].fromgrid);    
            data[0].fromgrid = history.kwhsNow[0].fromgrid - data[0].fromgrid - history.kwhsToday[0].fromgrid - history.kwhsDayAgo[0].fromgrid - history.twoDaysAgo[0].fromgrid - history.threeDaysAgo[0].fromgrid - history.fourDaysAgo[0].fromgrid - history.fiveDaysAgo[0].fromgrid - history.sixDaysAgo[0].fromgrid;  
            callback (null, data);
            res.json(history); 
            console.log(history);// return all in JSON format
        });
    } 
};

Async.parallel (history, function (err, results) {

    if (err)
        throw err;

    //results holds the data in object form
    console.log(results);

});

EDIT: Async.Parallel executes the functions passed to it simultaneously. If you want to have them executed one after the other, use Async.Series. This way, you will be able to access the results returned by the previous functions as well. However, you will have to pass the functions in an array instead of an object.

5
  • Thanks for the fast response. I have been reading up on the async module. I have updated the code but each function is still being fired async which means I run into the same issue when manipulating the data in order I have written the code. When I comment out the calculations (subtractions) the object is populated but not in order.
    – Matt
    Commented Apr 7, 2015 at 17:16
  • { kwhsNow: [ { _id: 1428426599000, fromgrid: 54137719 } ], kwhsFourDaysAgo: [ { _id: 1428044400000, fromgrid: 54022614 } ], kwhsToday: [ { _id: 1428390000000, fromgrid: 54123738 } ], kwhsFiveDaysAgo: [ { _id: 1427958000000, fromgrid: 53997075 } ], kwhsDayAgo: [ { _id: 1428303600000, fromgrid: 54092976 } ], kwhsSixDaysAgo: [ { _id: 1427871602000, fromgrid: 53975853 } ], kwhsTwoDaysAgo: [ { _id: 1428217200000, fromgrid: 54063325 } ], kwhsSevenDaysAgo: [ { _id: 1427785200000, fromgrid: 53954110 } ], kwhsThreeDaysAgo: [ { _id: 1428156300000, fromgrid: 54048604 } ] }
    – Matt
    Commented Apr 7, 2015 at 17:17
  • I assume this is the nature of how node works and each db query returns at different times which explains why kwhsToday is undefined in the kwhsFourDaysAgo function. I will remove my calcs from each function and manipulate the data at the end.
    – Matt
    Commented Apr 7, 2015 at 17:25
  • Yes. Node is designed to be used Asynchronously. Instead of Parallel, use Async.Series. This will execute the the functions one after the other. You will be able to access the values gathered in previous queries as well.
    – ZeMoon
    Commented Apr 7, 2015 at 17:39
  • However, you will have to put these functions in an array.
    – ZeMoon
    Commented Apr 7, 2015 at 17:40

Not the answer you're looking for? Browse other questions tagged or ask your own question.