0
var count=0;
function test2(callback) {

db.doc("Kerala/Pathanamthitta")
.listCollections()
.then((snap) => {
  snap.forEach((collection) => {
    var col = collection.id;
    db.collection(`Kerala/Pathanamthitta/${col}`)
      .where("completionStatus", "<", 3)
      .get()
      .then((snapshot) => {
        snapshot.forEach((doc) => {
          var data = doc.data();
          console.log(data.place);
          if (data.completionStatus == 0) count++;
        });
      });
  });
})
.then(callback);
}
test2(function () {
 console.log(count);
});

I want to print the final count after the execution of test2 function. It prints the statement but always 0, even if any updation happens inside function test2. I tried to do a callback() but still the same happens Please help. Thanks in advance

2 Answers2

1

You're misunderstanding how asynchronous functions and promise chains works. You're calling a promise chain and the callback right after each other.

db.doc(...)...
callback()

This ends up executing like so:

db.doc
callback
db.doc.then

at this point you have called callback BEFORE the resolution of the promise chain. You want to put the callback in the promise chain so that it is delayed until after all of that has finished. A good spot would be in another promise chain after the outer loop for a single log of the eventual count.

...
.then(snap => {
  snap.forEach(collection => {...});
})
.then(callback);
...

This way after you've finished going over all of the snaps and finished counting the snapshots you'll print out the count in the correct order after both traversals.

BUT WAIT it's still printing 0. Why is that? Well we're not properly chaining our promises. We'll need to make sure that any promises we create in a promise properly chain so that when we do get to the logging step we've got a proper chain going.

Full code:

var count = 0;
function test2(callback) {
  db.doc("Kerala/Pathanamthitta")
    .listCollections()
    .then((snap) => {
      return Promise.all(
        snap.map((collection) => {
          var col = collection.id;
          return db
            .collection(`Kerala/Pathanamthitta/${col}`)
            .where("completionStatus", "<", 3)
            .get()
            .then((snapshot) => {
              return Promise.all(
                snapshot.map((doc) => {
                  var data = doc.data();
                  console.log(data.place);
                  if (data.completionStatus == 0) count++;
                })
              );
            });
        })
      );
    })
    .then(callback);
}
test2(function () {
  console.log(count);
});
Robert Mennell
  • 1,954
  • 11
  • 24
  • I like this more, fix the existing issue rather than avoid it. – Dane Brouwer May 09 '20 at 19:14
  • But I like to get a single print log only. If i place function call statement just after snapshot I may end up getting may log statements. I just need the final count – Jerin Joseph May 09 '20 at 19:26
  • @JerinJoseph okay I'll update the answer – Robert Mennell May 09 '20 at 19:31
  • Thank you @RobertMennell – Jerin Joseph May 09 '20 at 19:32
  • @JerinJoseph updated to use a chain after the snaps instead of the snapshots – Robert Mennell May 09 '20 at 19:36
  • I thought it worked but I got an error instead `UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'then' of undefined` @RobertMennell – Jerin Joseph May 09 '20 at 19:49
  • @JerinJoseph added the full code to the end to show where it should go. if that doesn't work comment again and we'll move to a discussion – Robert Mennell May 09 '20 at 19:54
  • `function test2(callback){ var count=0; db.doc('Kerala/Pathanamthitta').listCollections().then((snap) => { snap.forEach((collection) => {var col=collection.id; db.collection(`Kerala/Pathanamthitta/${col}`).where('completionStatus', '<',3).get().then(snapshot => { snapshot.forEach(doc => {var data=doc.data(); if(data.completionStatus==0) count++; }); }); }); }).then(callback(count)); } test2(function(count) {console.log(count);})` Got no error but still the count value prints 0. @RobertMennell – Jerin Joseph May 09 '20 at 19:57
  • don't call callback in the then, just put callback there. Compare your code to the full code I posted. You call callback then pass that result to `.then` when you should just be passing the callback function to the `.then` without calling it as the then will call it – Robert Mennell May 09 '20 at 20:03
  • It still logs the output as 0 and I think the console.log(count) was first executed before test2 function as well because 0 was logged even before the console.log(data.place) @RobertMennell – Jerin Joseph May 09 '20 at 20:28
  • then there are other code problems we need to look into solving(improper promise chaining looks to be the cause) – Robert Mennell May 09 '20 at 20:29
  • I've updated it in a way that should help, but to continue further troubleshooting we'll really want to hop into a chat. Comments aren't a good place to have indepth discussions – Robert Mennell May 09 '20 at 20:35
  • Thank you so much for your help. But I met with another error now, TypeError: snapshot.map is not a function @RobertMennell – Jerin Joseph May 09 '20 at 20:48
  • then there's a lot of things that are going to be a lot deeper of a dive for this. I don't think we'll be able to continue any further as it seems there's some massive missing tools under your belt. I'd suggest reading up on the promise specification and your DB tools documentation – Robert Mennell May 09 '20 at 20:49
  • Thanks @RobertMennell – Jerin Joseph May 09 '20 at 20:51
  • `var count=0; function test2(callback) {db.doc("Kerala/Pathanamthitta").listCollections().then((snap) => {return Promise.all(snap.map((collection) => { var col = collection.id; return db .collection(`Kerala/Pathanamthitta/${col}`).where("completionStatus", "<", 3).get().then((snapshot) => {snapshot.forEach((doc) => {var data = doc.data(); console.log(data.place); if (data.completionStatus == 0) count++; ); }).then(callback); } test2(function () {console.log(count);});` This worked for me @RobertMennell – Jerin Joseph May 10 '20 at 04:45
  • what you pasted has syntax errors. Is that your exact code? – Robert Mennell May 10 '20 at 05:01
0

As per my comment, you could just make a function call after you're done counting.

//content above
snapshot.forEach(doc => {
  var data = doc.data();
  console.log(data.place);
  if (data.completionStatus == 0) count++;
});
functionTwo(count);
// content below

functionTwo(count) {
  console.log(count);
}
Community
  • 1
  • 1
Dane Brouwer
  • 2,827
  • 1
  • 22
  • 30
  • But what if I would like the first forEach operation snap.forEach(collection => to complete, or else I think there will be a number of log statements executed – Jerin Joseph May 09 '20 at 19:16