1

I have this code in node js / firebase :

ref.child("recipts").once("value", function(usersSnap) {
    usersSnap.forEach(function(reciptsSnap) {  
      reciptsSnap.forEach(function(reciptSnap) {

        reciptSnap.ref.child("last_recipt").once("value", function(b) {
          b.forEach(function(c) {  //Here I fill some "product" object
              });
        });

        reciptSnap.forEach(function(b) { //Here I fill some "product" object
        });

      });
    });
  });

I need to execute a function just when "reciptSnap" forEachs finished. How can I accomplish this, I try using a variable i++ and i-- but only work for one forEach iteration. The function I call is for manipulating the product object I created with the filled data from the forEachs loops.

3
  • 1
    I'm not familiar with firebase, but it doesn't seem strictly related to it. If the operations you run inside the forEach are async operations, then you can't do what you're trying to do in a proper way. The better way would be to use promises in an array, and execute them using Promise.all(): developer.mozilla.org/en/docs/Web/JavaScript/Reference/… Commented Jan 26, 2017 at 7:56
  • I started writing an answer, but got really confused in what this code is trying to do and what the data structure looks like. Can you share a small snippet of the JSON (as text, no screenshots) that this code handles? You can get this by clicking the "Export JSON" link in your Firebase Database console. Commented Jan 26, 2017 at 8:55
  • Are you sure you need to do reciptSnap.ref.child("last_recipt").once("value" ? That data should already have been included when fetching "value" on your receipts node. Try reciptSnap.child("last_recipt").forEach( instead. If that works, your code is no longer async, and when the inner foreach is finished, all will be good. Commented Jan 26, 2017 at 9:12

2 Answers 2

2

If I have understood correctly, you want to call a function when reciptsSnap.forEach is complete and all async tasks inside it are also complete.

For achieving this, you can use the index parameter and the original array that is passed to the callback function of forEach. (See Documentation)

The code will be like this:

(Note: The following code is without changing the current forEach loop structure used. However, re-writing the code with Promise or async would be a better & cleaner way to do it).

var loop1Done = false;
var loop2Done = false;

ref.child("recipts").once("value", function (usersSnap) {
    usersSnap.forEach(function (reciptsSnap) {
        reciptsSnap.forEach(function (reciptSnap, index, colA) {

            const idx = index;
            const col = colA;

            reciptSnap.ref.child("last_recipt").once("value", function (b) {

                const i = idx;
                const c = col;

                b.forEach(function (c, j, colB) {  //Here I fill some "product" object

                    // Do what you want here

                    // Check if all done for this loop
                    if ((j >= colB.length) && (i >= c.length)) {

                        loop1Done = true;

                        // Check if all loops done
                        if (loop1Done && loop2Done) {
                            // Call final callback function
                            // e.g. myFinalCallback();
                        }
                    }
                });
            });

            reciptSnap.forEach(function (b, k, colC) { //Here I fill some "product" object

                const i = idx;
                const c = col;

                // Do what you want here

                // Check if all done for this loop
                if ((k >= colC.length) && (i >= c.length)) {

                    loop2Done = true;

                    // Check if all loops done
                    if (loop1Done && loop2Done) {
                        // Call final callback function
                        // e.g. myFinalCallback();
                    }
                }
            });

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

4 Comments

Could you please give me an example with async or promises I cant reach the implementation
Can you first confirm if this worked for you? So that I can be sure that I have understood your requirement correctly.
I see what youre trying to get but one forEach marks me error : at C:\Users\asasas-api\routes\cronSubscription\index.js:76:33
Please provide complete error. Which line is throwing error? What error message?
1

Try:

   reciptSnap.child("last_recipt").forEach(function(b) {
      b.forEach(function(c) {
               //Here I fill some "product" object
      });
   });

This should work since all of your data should already have been fetched when you did "value" on the receipts node.

If this works, your code is no longer asynchronous and right after the last forEach, you can execute the function you wanted to.

    reciptSnap.forEach(function(b) {
        //Here I fill some "product" object
    });
    //Execute your function here
  });

Comments

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.