1

I am using expressJs to route some POST requests. From the client side I pass an object of objects and in the server I iterate over each of them with a for loop.

My problem, the variable cantidad in the loop only takes the first value instead of being refreshed into the pool.query, but before the pool.query it takes the right value.

So, the line below is ok.

console.log("cantidad before query: " + cantidad);

But the line below is bad. It has the first value.

console.log("cantidad in query: " + cantidad);

This is part of my code.

for (var key in objects) {
if (objects.hasOwnProperty(key)) { 
    ...
    console.log("cantidad before query: " + cantidad);
    pool.query(qProducto,idProducto, function (error, results, fields {
    if (error) {
    ...
} else {
    console.log("cantidad in query: " + cantidad);
    ...

This is the full POST in ExpressJs.

app.post("/commanda", function (req, res) {
var idCuenta = req.body.idCuenta;
var idEmpleado = req.body.idEmpleado;
var fechaRegistro = req.body.fechaRegistro;
var cuenta_mesero = "C:" + idCuenta + ":E:" + idEmpleado;
var objects = req.body.objects;
var element = {};
for (var key in objects) {
  if (objects.hasOwnProperty(key)) {
        var qProducto = "SELECT descripcionProducto FROM PRODUCTO WHERE idProducto = ? ;";
        var descProducto = '';
        console.log("cantidad in commanda2 : " + objects[key].cantidad );
        try {
            pool.query(qProducto, objects[key].idProducto, function (error, results, fields) {
            if (error) {
                console.error(error);
                console.error("Failed with query: " + qProducto);
                res.status(500).end();
                throw error;
            } else {
                console.log("cantidad in commanda4 : " + objects[key].cantidad );
                descProducto = JSON.stringify(results[0].descripcionProducto);
                element = {
                    idProducto:objects[key].idProducto,
                    cantidad:objects[key].cantidad,
                    descProducto:descProducto,
                    cuenta_mesero:cuenta_mesero,
                    fechaRegistro:fechaRegistro
                };
                imprimirOrden(element);
                }
            });
        } catch (error) {
        callback(error);
        }
  }
}
printer.printVerticalTab();
res.status(200).end();
});

This is how an object looks like.

{ '0':
   { idProducto: '28',
      cantidad: '3',
      descProducto: 'Product1',
      precioProducto: '3500',
      precioTotal: 10500,
     '$$hashKey': 'object:345' },
 '1':
   { idProducto: '29',
      cantidad: '2',
      descProducto: 'Product2',
      precioProducto: '4500',
      precioTotal: 9000,
      '$$hashKey': 'object:346' } }

1 Answers1

3

This happens because the function for is synchronous but the function poll.query is asynchronous. What this means is that using the for loop you are essentially queuing some queries. You are not executing them one by one. So the for loop will finish before even one result is returned from the query. If you want to use data from the query for the next iteration you should start using async.js, an npm module that helps you avoid this problems. TL;DR the console log that you think runs in query is actually run before even one query has finished. More information is needed on where you declare the variable cantidad and when you change it to accurately understand the problem.

UPDATE: What I told you at first was quite wrong because of the fact that I misunderstood the in-detention of the else {}. But what I told you already is actually the problem. It was well obfuscated.The for loop finishes before even one query has finished. They are just queued. So the second console.log will have the key of the last key in the loop. If you need logic that requires knowing in which iteration you are you should implement an async function in order to know in which iteration you actually are. If you don't want to use the async library you can use something like this.

First add this function in the bottom of your js file https://pastebin.com/4tR0xaTY

You essentially created an async for loop that you can now know in which iteration you are using loop.iteration(). Then replace your post code with the code written below ( To include the async loop ). https://pastebin.com/YzZU7bqp

itsundefined
  • 1,409
  • 2
  • 12
  • 32
  • Ok, do you have an idea how can it be implemented? using async.parallel? series? waterfall? eachSeries? Actually, my variable `cantidad` is not a result from the query but part of the object `objects`. The result from query is another variable that is successfully being updated. – JeanCarlos Chavarria Apr 16 '17 at 19:45
  • Are you changing the variable cantidad based on the results of the query? If yes then I believe the series function is what you are looking for. It will make sure to call each query after the previous one has finished. – itsundefined Apr 16 '17 at 19:47
  • After reading your edited comment I still do not understand the problem. In which part of the code are you changing the variable cantidad? Because you stated that only the first value is console logged. – itsundefined Apr 16 '17 at 19:53
  • No, I dont. I have an object of objects. Each object has its own `cantidad` variable. I need to iterate each of them into the `else{}` of `pool.query`. I have added the full POST method to have it clearer. – JeanCarlos Chavarria Apr 16 '17 at 19:54
  • This makes sense. The identantion you used before the edit made me think that the else{} is part of the if (objects.hasOwnProperty(key)) {}. Let me take a look. Seems like the problem is not lying in what I explained before. – itsundefined Apr 16 '17 at 19:57
  • I have posted how on object looks like – JeanCarlos Chavarria Apr 16 '17 at 19:59
  • After taking a look everything seems correct. But as I explained before the two console.logs will run in a strange order. You should first see all the iterations logged in the first console.log ( since it will run from the synchronous function for ) but then you should expect to see all the iterations ( maybe in a random order since the second query could finish before the first ) from the second console.log. Are you implying that the second console.log only returns the result of the first key multiple times or a single time and then silence? – itsundefined Apr 16 '17 at 20:07
  • I just registered today in stackoverflow so i dont know how to use code. I posted the solution ( I did not test it ) using pastebin (unlisted) above. I am sorry if my english is bad but I faced the same issue yesterday and I fixed it this way so I decided to help – itsundefined Apr 16 '17 at 20:42
  • Thank you very much, your advice worked in the first instance with the function `asyncLoop` . Now I need to read a lot about this to fully understand the issue. If you have some literature to recommend will be very useful. Thank you very much. – JeanCarlos Chavarria Apr 17 '17 at 01:51
  • I do not know of any good explanation for mixing sync and async functions but there are many solutions apart from using an asyncLoop in this question: http://stackoverflow.com/questions/13343340/calling-an-asynchronous-function-within-a-for-loop-in-javascript – itsundefined Apr 17 '17 at 10:36