1

I have a firestore collection containing post documents, each document contains a reference to an author (user) and a case document.

How do I get the user and the case in the same onSnapshot?

Here's what I'd like to do with await, but that doesn't seem to be an option with react-native-firebase.

export const firebasePostLooper = (snapshot) => {
  let data = [];

  snapshot.forEach(async (doc) => {
    let newItem = {id: doc.id, ...doc.data()};
    if (newItem.author) {
      let authorData = await getDoc(newItem.author); // doesn't work with rnfirebase
      if (authorData.exists()) {
        newItem.userData = {userID: authorData.id, ...authorData.data()};
      }
    }
    if (newItem.case) {
      let caseData = await getDoc(newItem.case);
      if (caseData.exists()) {
        newItem.userData = {userID: caseData.id, ...caseData.data()};
      }
    }
    data.push(newItem);
  });
  return data;
};

This doesn't work because getDoc() doesn't exist.

So I'm left with using .then()


export const firebasePostLooper = (snapshot) => {
  let data = [];

  snapshot.forEach((doc) => {
    let newItem = {id: doc.id, ...doc.data()};

    if (newItem.author) {
      newItem.author
        .get()
        .then((res) => {
          newItem.authorData = res.data();
          if (newItem.case) {
            newItem.case
              .get()
              .then((caseRes) => {
                newItem.caseData = caseRes.data();
                data.push(newItem);
              })
              .catch((err) => console.error(err));
          }
        })
        .catch((err) => console.error(err));
    } else {
      data.push(newItem);
    }
  });
  return data;
};

This second method doesn't seem to be working, data is empty at the return statement but data.push(newItem) contains the correct document with the 2 referenced documents.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
Mel
  • 625
  • 9
  • 25
  • Data is loaded from Firestore (and most modern cloud APIs) asynchronously, and by the time your `return data` runs, the `data.push(newItem)` hasn't been called yet. You can most easily check this by setting breakpoints on those lines and running in a debugger, or by adding some log statements and checking in which order they are output. See for example: https://stackoverflow.com/questions/60691965/unable-to-add-google-markers-inside-a-loop/60694259#60694259 – Frank van Puffelen Jan 19 '22 at 15:39

1 Answers1

1

You're returning data before it gets filled inside the promise. You should handle the returning of the data inside a .then() in order to return it after the promise has resolved and not before.

Take a look at this example where if we handle the emptyData object outside the promise chain, we just return the initial value before it has been filled.

let promise = new Promise((resolve, reject)=>{
setTimeout(resolve, 1000, 'foo');
})

let emptyData= [];
let notEmptyData = [];

promise
.then(res=>{
    emptyData.push(res);
  notEmptyData.push(res);
    console.log("Full data: " + notEmptyData) // "Full data: foo"
});



console.log("Empty data: " + emptyData); // "Empty data: "