Home > Back-end >  Node.js and MySQL. forEach() inside Promise - last item is not being inserted in array
Node.js and MySQL. forEach() inside Promise - last item is not being inserted in array

Time:12-06

I'm having trouble pushing the last element of a query inside an array.

  • The program should loop through the testArray and search inside the database for the corresponding MedikamentId
  • and then create an array of those IDs.

This almost works and the output currently looks like this: [3,2,3,2,3,2,3,2,3,2,3,2,3]

But the last element is missing, there should also be a 2 at the end of this array (in sum there must be 14 elements).

When I run the console.log(medIdArray) which is commented inside the loop I get the correct array.

Why is my last item not being returned when I put the medIdArray inside the .then() handler?

let testArray = [
  ['Pantoprazol','Ibuprofen'],
  ['Pantoprazol','Ibuprofen'],
  ['Pantoprazol','Ibuprofen'],
  ['Pantoprazol','Ibuprofen'],
  ['Pantoprazol','Ibuprofen'],
  ['Pantoprazol','Ibuprofen'],
  ['Pantoprazol','Ibuprofen'],
];

let medIdArray = [];
let sqlGetMedId = "SELECT MedikamentId FROM Medikament WHERE Bezeichnung = ?";
let getMedId = new Promise((resolve, reject) => {
  testArray.forEach((i, idx, array) => {
    i.forEach((j) => {
      mySqlConnection.query(sqlGetMedId, j, (err, rows, fields) => {
        if (err) reject(err);
        medIdArray.push(rows[0].MedikamentId);
        //console.log(medIdArray);
        if (idx === array.length-1) resolve();
      })
    })
  })
})

getMedId.then(() => {
  console.log(medIdArray);
})

getMedId.catch((err) => {
  console.log(err);
})
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

This line of code

if (idx === array.length-1) resolve();

resolves the promise at the first iteration for the inner loop instead of the second. Use

i.forEach((j, idx2) => {
   ...
   if (idx === array.length-1 && idx2 === i.length -1) resolve();
}

or something similar ...

EDIT

But instead of nesting loops you proably could flatten your input array first and that iterate over the flattened array

let testArray = [[..], [..]];
let flattened = testArray.reduce((a, c) => {
  a.push(...c);
  return a;
}, [])

return new Promise((resolve, reject) => {
   flattened.forEach((elem, idx) => {
     con.query(..., (err, rows, fields) => {
       ...
       if (idx === flattened.length - 1) resolve();
     });
   });
});

or you could also use Promise.all

let getIds = Promise.all(flattened.map(med => new Promise((res, rej) => { 
  conn.query(..., med, (err, rows, fields) => {
    if (err) rej(err);
    res(rows[0].MedikamentId);
  });
})));

getIds.then(data => {
  //data is an array of query results 
});
  • Related