Home > Software design >  Fetching Firebase Firestore References
Fetching Firebase Firestore References

Time:02-01

Suppose I have the following Firestore data structure:

collection tickets

{
    name: "Testticket",
    open: true,
    users: [
        "users/abcdefg1234" // Firestore reference
    ]
}

collection users

{
    name: "John Doe",
    color: "green"
}

My goal is to get all the tickets where open is true, including the user object istead of the reference.

Currently I am doing this:

// Firebase Functions node.js code

async function getUserData(item) {
  const queryResult = await item.get();
  return await queryResult.data();
}

exports.getOpenTickets = async (request, response) => {
  const query = await db.collection("tickets").where("open", "==", true).get();

  let tickets = [];
  query.forEach(async (doc) => {
    let data = doc.data();
    console.log("data", data);

    data.userObjects = await Promise.all(data.users.map(getUserData));
    console.log("data.userObjects", data.userObjects);

    tickets.push(data);
  });

  return response.json(tickets);
};

Problem: The user data is fetched but the main function is not waiting for it (checked with console log statements).

This is my node.js console log:

i  functions: Beginning execution of "api"
!  Google API requested!
   - URL: "https://oauth2.googleapis.com/token"
   - Be careful, this may be a production service.
>  data {
>    open: true,
>    name: 'Testticket',
>    users: [
>      DocumentReference {
>        _firestore: [Firestore],
>        _path: [ResourcePath],
>        _converter: [Object]
>      }
>    ]
>  }
i  functions: Finished "api" in 1069.554ms
>  data.userObjects [ { color: 'green', name: 'John Doe' } ]

How to fix this?

CodePudding user response:

If you want to run asynchronous operations within a loop, then you should not use forEach. Try refactoring the code using for of loop as shown below:

exports.getOpenTickets = async (request, response) => {
  const snap = await db.collection("tickets").where("open", "==", true).get();
  let tickets = [];
  
  for (const doc of snap.docs ) {
    let data = doc.data();
    console.log("data", data);

    data.userObjects = await Promise.all(data.users.map(getUserData));
    console.log("data.userObjects", data.userObjects);

    tickets.push(data);
  }

  return response.json(tickets);
};

Also checkout Using async/await with a forEach loop.

  • Related