0

I have an array. I want to query a mysql database with each array element and on a certain condition fulfillment, I want to add additional elements to the same array and iterate through those elements as well.

I'm new to nodejs so I don't know if this is the right approach.

I have provided a code snippet that is a simplified version of my issue.

In below code snippet, I want to display "looks good" on console.

pre_req_subjects_arr = [2310,2320,2410];
for(let j=0;j<pre_req_subjects_arr.length;j++) {
    console.log("j is : "+j);
    db.query("SELECT `NUMBER` FROM `COURSE`",function(err,preOfPreReq) {
        if(err) {
            console.log("Error while creating array of pre_req subjects : " + err);
        } else {
            console.log("j inside db query : "+j);
            if(j==1) {
                pre_req_subjects_arr.push(1111);    
            }
            if(pre_req_subjects_arr[j] == 1111) {
                console.log("looks good");
            }
        }
    })                                        
}

setTimeout(function() {
    console.log("pre_req_subjects_arr is " + JSON.stringify(pre_req_subjects_arr));
}, 1000);

Output:

j is : 0
j is : 1
j is : 2


j inside db query : 0
j inside db query : 1
j inside db query : 2



pre_req_subject_arr : [2310,2320,2410,1111]

Expected Output:

j is : 0
j is : 1
j is : 2
j is : 3

j inside db query : 0
j inside db query : 1
j inside db query : 2
j inside db query : 3 

looks good  
pre_req_subject_arr : [2310,2320,2410,1111]
6
  • Does your database API (which is it?) support promises? Commented Jan 29, 2019 at 13:15
  • I am using mysql database. Commented Jan 29, 2019 at 13:18
  • Your code doesn't make much sense. Making the same query 3 times and adding to an array if j equals 1? Commented Jan 29, 2019 at 13:18
  • My actual code will add elements to the array from db results and then again fire a query with the added element. This is just the simplified version Commented Jan 29, 2019 at 13:22
  • @vijju, I did not mean which database, but which package you use to connect to the database. Commented Jan 29, 2019 at 13:28

4 Answers 4

3

Because your database API is asynchronous, your for loop will already have completed before any of the db.query callbacks have executed. So when you push there, it is already too late for the for loop -- it already exited.

You should look into promises, and possibly your database API supports promises. In that case, use that capability. But from comments I understand you use the mysql package which does not have promise support.

The principle (with or without promises) is that you wait for each query to complete before proceeding with the next "iteration". You'll need some way of asynchronous looping to achieve that. You can for instance use this function:

var pre_req_subjects_arr = [2310,2320,2410];

(function loop(j) {
    if (j >= pre_req_subjects_arr.length) {  // all "iterations" done!
        console.log("pre_req_subjects_arr is " + JSON.stringify(pre_req_subjects_arr));
        return;
    }
    console.log("j is : "+j);

    db.query("SELECT `NUMBER` FROM `COURSE`",function(err,preOfPreReq) {
        if(err) {
            console.log("Error while creating array of pre_req subjects : " + err);
        } else {
            console.log("j inside db query : "+j);
            if(j==1) {
                pre_req_subjects_arr.push(1111);
            }
            if(pre_req_subjects_arr[j] == 1111) {
                console.log("looks good");
            }
        }
        loop(j+1); // Only now call the next "iteration"
    })                 
})(0); // start the first iteration

Alternatively you can promisify the query method and then use the power of await:

// Create a promisified version of db.query
const queryPromise = (db, sql) => 
    new Promise((resolve, reject) => 
        db.query(sql, (err, result) => err ? reject(err) : resolve(result))
    );

// Now you can use async/await and a for-loop
(async function () {
    const pre_req_subjects_arr = [2310,2320,2410];

    for (let j = 0; j < pre_req_subjects_arr.length; j++) {
        console.log("j is : "+j);
        try {
            const preOfPreReq = await queryPromise(db, "SELECT `NUMBER` FROM `COURSE`");
            console.log("j inside db query : "+j);
            if (j==1) {
                pre_req_subjects_arr.push(1111);
            }
            if (pre_req_subjects_arr[j] == 1111) {
                console.log("looks good");
            }
        } catch(e) {
            console.log("Error while creating array of pre_req subjects : " + e);
        }
    }
    console.log("pre_req_subjects_arr is " + JSON.stringify(pre_req_subjects_arr));
})();

NB: As a side note: it is generally a bad idea to perform an SQL query in a loop. Usually you can replace that by a single, smarter query.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much @trincot for your help. This code snippet solves the problem.
0

setTimeout is never a good way to do.

if you need it, you have to review the logic of your code

2 Comments

Thank you Nathan!!
I did not say that to be mean huh ;)
0

The issue is the for loop doesn't wait for the callback to get completed for each iteration. Since your database doesn't support promises, you can wrap the query inside a promise,

(async () => {
  let pre_req_subjects_arr = [2310, 2320, 2410];
  for (const [j, value] of pre_req_subjects_arr.entries()) {
    console.log("j is : " + j);
    const preOfPreReq = await executeQuery("SELECT `NUMBER` FROM `COURSE`");
    console.log("j inside db query : " + j);
    if (j == 1) {
      pre_req_subjects_arr.push(1111);
    }
    if (pre_req_subjects_arr[j] == 1111) {
      console.log("looks good");
    }
  }
  console.log(
    "pre_req_subjects_arr is " + JSON.stringify(pre_req_subjects_arr)
  );
})();

const executeQuery = queryStr => {
  return new Promise(function(resolve, reject) {
    db.query(queryStr, function(err, results) {
      if (err) {
        return reject(err);
      }
      return resolve(results);
    });
  });
};

3 Comments

Hey @shradha , Please can you tell me how to check if my package supports promises?
@viju The mysql package that you are using doesn't support promises, so you can wrap the db query inside a promise and use async/await.
Thank you @shradha.
-1
const preReqSubjectsArr = [2310, 2320, 2410];

let condition = true;

for (let j = 0; j < preReqSubjectsArr.length; j++) {
  console.log('j is : ' + j);

  db.query('SELECT `NUMBER` FROM `COURSE`', function(err, preOfPreReq) {
    if (err) {
      console.log('Error while creating array of pre_req subjects : ' + err);
    } else {
      if (condition === true && j === 1) {
        condition = false;

        preReqSubjectsArr.splice(j, 0, 1111);

        j--;
      } else {
        console.log('j inside db query : ' + preReqSubjectsArr[j]);
      }

      if (preReqSubjectsArr[j] === 1111) {
        console.log('looks good');
      }
    }
  });
}

setTimeout(function() {
  console.log('preReqSubjectsArr ', JSON.stringify(preReqSubjectsArr));
}, 1000);

output:

j is : 0
j inside db query : 2310
j is : 1
j is : 1
j inside db query : 1111
looks good
j is : 2
j inside db query : 2320
j is : 3
j inside db query : 2410
preReqSubjectsArr  [2310,1111,2320,2410]

I hope I understood the task correctly!

2 Comments

Be aware that the loop will not wait until the asynchronous function is executed! db.query looks like an asynchronous function! :)
Welcome to SO. it's a terrible idea to use setTimeout to wait for asynchronous results. Use promise instead.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.