I am very new to Node js and asynchronous programming seems difficult for me to grasp. I am using promise-mysql to make the flow synchronous but I have hit a road block with for loop inside of a chain of promise
I have a multiple choice question module. One table stores all the mcq questions and the other stores all the related choices for the questions. I am using the output of the first query as an input to the second query and so I did promise chaining as below
var mcqAll=[]
var sql_test_q_ans='select qId, q_text from questions'
con.query(sql_test_q_ans)
.then((result)=>{
for(var i=0; i<result.length; i++)
{
ques=result[i]
var sql_test_q_ops='SELECT op_text, op_id FROM mc_ops WHERE
q_id='+result[i].q_id
con.query(sql_test_q_ops)
.then((resultOps)=>{
mcqAll.push({i: ques, ops: resultOps})
console.log(mcqAll)
})
}
})
I am trying to create a javascript object array which would look something like this
[{q_text:'How many states in USA', q_ops:{1:25, 2:35, 3:45, 4:50}}
{question2 and its options}
{question3 and its options}....
]
When I run the above code the object populates all the question's options correctly but the same question is repeated in all the q_text for all questions.
[ { q_text: 'No of states in USA',
[ {op_text: '25', mc_op_id: 113 },
{ op_text: '35', mc_op_id: 114 },
{ op_text: '45', mc_op_id: 115 },
{ op_text: '50', mc_op_id: 116}],
{ q_text: 'No of states in USA',
[ {op_text: 'A', mc_op_id: 1 },
{ op_text: 'B', mc_op_id: 2 },
{ op_text: 'C', mc_op_id: 3 },
{ op_text: 'D', mc_op_id: 4}],
{ q_text: 'No of states in USA',
[ {op_text: 'Yes', mc_op_id: 31 },
{ op_text: 'No', mc_op_id: 32 },
{ op_text: 'No sure', mc_op_id: 33 },
{ op_text: 'Might be', mc_op_id: 34}]
]
I feel like it has something to do with asynchronous flow since console.log before the second query gets printed in all before printing anything after the second query. Any insight would be appreciated
Edit: I added a sample output for better understanding. As seen in the output, the options change and get stored in the js object in the for loop but the question is updated for all the objects to the last question in the for loop
You have a scope problem here
This is an example to reproduce your problem:
ques
is a global variable that is updated in the for-loop so, when the async code ends the execution will read the global variable with the lastques = result[i]
value.But, if you simply declare the
ques
like this:all will work.
It is a good practice to use
const
orlet
instead ofvar
because the last one creates a global scoped variable that is dangerous.Regarding your comment: the output is empty because this for-loop is sync, so you reply in sync way to the response.
An example on how to manage this case could be like this:
Consider that there are many possibilities to implement this:
in
condition instead of a query for eachq_id
and manage the result with some code to group the resultsGo deeper and choose the one that fits best for your need.
Important:
.catch
always the promise chain!