1

I have written a function that loops over an object and uses array.push(XYZ) to append the value (XYZ) to the array (array). After the loop is complete the function returns a promise. When I use myFunction().then(function(response) { console.log(response[0])}), I get undefined in the console. When I type in console.log(response[0]) in the console, I get the correct value. What am I doing wrong? I think that it is taking time to push the value into the array but I am not 100%. Any help will be appreciated.

My Code (I have not included the code defining db but it is not important as getting the info from the database is working fine.)

function getChild(uid) {
    promise = db.collection("users").doc(uid).get().then(function(doc) {
      output = [];
      val = doc.data();
      studentsObj = val.students;
      studentsObj.forEach(function(student) {
        db.collection("students").doc(student).get().then(function(res) {
          varl = res.data()
          output.push(varl);
        });
      });
      return output;
    });
    return promise;
};

getChild("parentUserID").then(function(reply) {
  got = reply;
  console.log(got);
});
B. Sommer
  • 63
  • 1
  • 7
  • It's not the time to call `push`, its the time to call `db.collection("students").doc(student).get()`. That's asynchronous. You will return the empty output before it returns. – Mark Jul 01 '18 at 20:40

1 Answers1

1

Asynchronous operations inside a forEach won't be chained with the outer Promise chain - use map instead to create an array of Promises, and then you need to return a Promise.all so that the promises generated by each studentsObj are properly chained. You should also try to avoid implicitly creating global variables - use const instead.

Try something like this:

const getChild = (uid) => (
  db.collection("users").doc(uid).get()
  .then(doc => {
    const { students } = doc.data();
    return Promise.all(students.map(student => (
      db.collection("students").doc(student).get()
      .then((res) => res.data())
    )))
  })
);

Or, using async functions instead to make the code a bit flatter:

const getChild = async (uid) => {
  const doc = await db.collection("users").doc(uid).get();
  const { students } = doc.data();
  return Promise.all(students.map(async (student) => {
    const res = await db.collection("students").doc(student).get();
    return res.data();
  )));
};
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320