Search code examples
javascriptecmascript-6google-cloud-firestorepromisees6-promise

How to wait until all of Promise are fulfilled?


My goal is to get the data from the field with a reference data type in a Firestore document. I use nested promise to get the data. The current code did not wait until all of the Promises are fulfilled.

How to make results.push( object ) wait until all of Promise is fulfilled?

expected results

data = {
  createdDate,
  expectedDate,
  customer_name = "John", // name from a document in `customer` collection.
  user_name = "Sherly", // name from a document in `user` collection.
}

actual results, the customer_name is "" instead of "John" which is fetched from a document in customer collection.

data = {
  createdDate,
  expectedDate,
  customer_name = "",
  user_name = "",
}
  firebase
    .firestore()
    .collection("sales_order")
    .get()
    .then(function (querySnapshot) {
      let results = [];
      querySnapshot.forEach(function (doc) {
        let data = doc.data();
        console.log(data);
        const createdDate = data.createdDate.seconds;
        // const deliveryDate = data.deliveryDate ? data.deliveryDate.seconds : null;
        const expectedDate = data.expectedDate.seconds;

        let customer_name = "";
        data.customer.get().then(function (doc) {
          if (doc.exists) {
            const { name } = doc.data();
            customer_name = name;
          }
        })

        let user_name = "";
        data.user.get().then(function (doc) {
          if (doc.exists) {
            const { name } = doc.data();
            console.log(name);
            user_name = name;
          }
        })

        results.push({
          id: doc.id,
          data: {
            createdDate,
            // deliveryDate,
            expectedDate,
            customer_name,
            user_name,
            // total,
            // invoiceStatus,
          },
        });
      });

      return results;
    })

edit: Reference: Basic knowledge to understand Promise

A community member suggested me to look up on the reference links and it does help you understand better more about Promise. Mr. trincot's answer is exactly what I am looking for although without the reference links, I could not understand how Promise works.

I appreciate both the anonymous community member and Mr. trincot to give me insight on how Promise works.


Solution

  • For the inner part of your loop, you could either chain the then calls and call push in the final then callback, or, you could combine the promises from two .get() lookups in a Promise.all argument.

    The outer loop should return a list of promises, which you then can feed to a Promise.all too. I would suggest to replace the forEach loop with a docs.map loop, which can return those promises.

    There is then no need to call push. The map call will create the array:

    Promise.all(firebase.firestore().collection("sales_order").get().then(function (querySnapshot) {
        return querySnapshot.docs.map(function (doc) {
            let data = doc.data();
            return Promise.all([data.customer.get(), data.user.get()]).then(function (docs) {
                return docs.map(doc => doc.exists ? doc.data().name : "");
            }).then(function ([customer_name, user_name]) { 
                return {
                    id: doc.id,
                    data: {
                        createdDate: data.createdDate.seconds,
                        expectedDate: data.expectedDate.seconds,
                        customer_name,
                        user_name,
                    },
                };
            });
        });
    })).then(function (results) {
        // deal with results here
    });