0

I am trying to iterate through a range of dates to return the top song for each date. So I have a for loop. Within this for loop a function is called to look through my database for the top song. Therefore I wrapped it in a promise in order that it would hold up the for loop, but this approach does not seem to work either. Can someone explain a better approach to solve this issue.

app.post('/getDate', function (req, res) {
      this.tracks = [];
      let until = new Date(req.body.dateToOutput);
      for (var d = new Date(req.body.dateFromOutput); d <= until; d.setDate(d.getDate() + 1)) {
            date = d.toLocaleDateString('en-US', { timeZone: 'UTC' });
            console.log('date', date);
            new Promise(function (resolve, reject) {
                  getDate(date).then(() => {
                        resolve();
                  })
            });
      }
      console.log(this.tracks);
});
function getDate(date) {
      return new Promise(function (resolve, reject) {
            Track.find({ Date: date }, function (err, track) {
                  if (!err) {
                        console.log(track);
                        this.tracks.push(track);
                        resolve();
                  }
                  else {
                        reject();
                  }
            }).sort({ Streams: -1 }).limit(1);
      });
}
Jonathan
  • 441
  • 1
  • 9
  • 28
  • I think your question has already been answered, check this: https://stackoverflow.com/questions/40328932/javascript-es6-promise-for-loop/40329190 – jogarcia Apr 15 '20 at 01:54
  • Also you are using a very strange for loop which can probably breaks or throw a bunch of errors, why not using numeric values?, i think my answer will not works if you don't repair the loop. – Layer Apr 15 '20 at 02:39
  • Ahhh another thing i forgot, in your getDate function you have .sort({Streams: -1}).limit(1), which will never be reflected in your code, because is done after the Track.find method is executed, but the return of your Track.find method i suspect is always undefined, and if isn't undefined, you are applyng it to something that will not be returned in the promise, so you are making operations that will not being reflected in your promise, is something like create a variable and not use it. – Layer Apr 15 '20 at 02:49

1 Answers1

1

I think the promise is not being executed, and also i think you are pointing to an undefined object in your getDate function, and the for loop doesn't waits to a promise to be solved or rejected. see this:

new Promise(function (resolve, reject) {
    getDate(date).then(() => {
        resolve();
    })
});

you are creating a new promise but you never execute this promise.

also in the function getDate you are pointing to an object that doesn't exists in his context:

this.tracks.push(track);

This will throw you some errors, because this.tracks is not part of getDate function is part of an anonymous function which is called by the app.post method.

so instead of pushing something in this.tracks directly, you must return the track itself:

if (!err) {
    console.log(track);
    resolve(track);
}

then you should use async - await to obligate the loop for make a pause at the promise until this being resolved or rejected, so your anonymous function, should be now an async anonymous function in order to use await, also you don't need a wrapper of a promise inside another promise, i mean you don't need this:

new Promise(function (resolve, reject) {
    getDate(date).then(() => {
        resolve();
    })
});

You only need this:

getDate(date).then(() => {
   resolve();
})

because the getDate() function returns a promise itself.

So this is how your code looks after making all these changes:

const response = app.post('/getDate', async function (req, res) {
      this.tracks = [];

      let until = new Date(req.body.dateToOutput);
      for (var d = new Date(req.body.dateFromOutput); d <= until; d.setDate(d.getDate() + 1)) {
            date = d.toLocaleDateString('en-US', { timeZone: 'UTC' });
            console.log('date', date);
            const ctrack = await getDate(date);
            this.tracks.push(ctrack);
      }

      console.log(this.tracks);
      return this.tracks;
});

function getDate(date) {
      return new Promise(function (resolve, reject) {
            Track.find({ Date: date }, function (err, track) {
                  if (!err) {
                        console.log(track);
                        resolve(track);
                  }
                  else {
                        reject();
                  }
            }).sort({ Streams: -1 }).limit(1);
      });
}

And now that you have the response as a promise, because an async function returns a promise... you can then and catch it and use the response:

response.then(trackList =>{
   console.log(trackList);
}).catch(()=>{
   console.error("something went wrong...!");
})
Layer
  • 326
  • 3
  • 12