6

I have firestore data somewhat like this:

"Support": { "userid":"abcdxyz", "message": "hello" }

I am using nodejs to fetch my data and I also want to show the email address and name of the person who sent this message. So I am using following function:

database.collection("support").get().then(async function (collections) {
var data = [];
console.log("data collected");
collections.forEach(async function (collection) {
    var temp = {};
    var collectionData = collection.data()
    var userInfo = await getUserDetails(collectionData.userId)
    temp.name = userInfo.name
    temp.supportMessage = collectionData.supportMessage
    data.push(temp)
    console.log("data pushed")
});
    console.log("data posted")
    return res.status(200).end(JSON.stringify({ status: 200, message: "Support Message fetched successfully.", data: data }))
}).catch(error => {
    return res.status(500).end(JSON.stringify({ status: 500, message: "Error: " + error }))
});

Here the sequence of logs is following: data collected, data posted, data pushed

I want the sequence like this: data collected, data pushed (x times), data posted

3
  • 1
    Possible duplicate of Using async/await with a forEach loop Commented Nov 5, 2018 at 6:21
  • 1
    The answer at that question suggests to use for -- of loop, and I can't use that in Firebase get. If you use it will say: TypeError: collections is not iterable Commented Nov 5, 2018 at 6:30
  • 2
    Then you need to convert it to an array first. WIth forEach or possibly toJSON. Also it's better to do things in parallel if possible with Promise.all and map Commented Nov 5, 2018 at 6:36

3 Answers 3

7

I solved my answer with the help of @estus comment.

Credit: @estus

var data = [];
var tempCollection = [];
collections.forEach(collection => {
    tempCollection.push(collection.data());
});
for (collection of tempCollection) {
    var temp = {};
    var userInfo = await getUserDetails(collection.userId)
    temp.name = userInfo.name
    temp.supportMessage = collection.supportMessage
    data.push(temp)
}

It solved my problem very easily.

Sign up to request clarification or add additional context in comments.

3 Comments

If your collection is big, you'll eat up all the available RAM of your device.
I'm doing the same thing but it appears to be working. But I've been warned there may be risks. Why is it necessary to do it like this? stackoverflow.com/questions/63996334/…
@estus can you still do this for .onSnapshot?
5

Use following code:

database.collection("support").get().then(async function (collections) {
var data = [];
console.log("data collected");

for await(let collection of collections){
  var temp = {};
  var collectionData = collection.data()
  var userInfo = await getUserDetails(collectionData.userId)
  temp.name = userInfo.name
  temp.supportMessage = collectionData.supportMessage
  data.push(temp)
  console.log("data pushed")
}

console.log("data posted")
return res.status(200).end(JSON.stringify({ status: 200, message: "Support Message fetched successfully.", data: data }))
}).catch(error => {
  return res.status(500).end(JSON.stringify({ status: 500, message: "Error: " + error }))
});

OR

Use can use

var promise = Promise.all(collections.map((collection) =>{
   ...
   return await ... //or a promise
}));

promise.then(() => {
  console.log("posted");
  return res.status(200).end(...);
})

Comments

4

I know this might not the OP's exact use case but if you're interested in compiling the results of a collection query into an array, you can still use the .docs property of a QuerySnapshot to obtain the list of items:

    ...
    const userId = <some-id>;
    const usersRef = db.collection(`users`)
    const usersSnapshot = await usersRef.where("id", "==", userId).get()

    if (usersSnapshot.empty) {
        console.log('found no matching user ', userId);
        return;
    }

    console.log(`found ${usersSnapshot.size} user records`);

    const userResults = []

    // this block here doesn't construct the results array before the return statement
    // because .foreach enumerator doesn't await: https://stackoverflow.com/q/37576685/1145905
    // usersSnapshot.forEach((doc) => {
    //     // doc.data() is never undefined for query doc snapshots
    //     //console.log(doc.id, " => ", doc.data());
    //     userResults.push[doc.data()];
    // });

    for (user of usersSnapshot.docs) {
        // console.log(user.id, " => ", user.data());
        userResults.push(user.data());
    }
    ...

A more detailed example is here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.