1

I'm having trouble with a Firebase cloud function where I'm trying to fetch data. This function:

 exports.fetchProducts= (req, res) => {
  db.collection("products")
    .where("active", "==", true)
    .get()
    .then(function (querySnapshot) {
      querySnapshot.forEach(async function (doc) {
        let data = [];
        // console.log(doc.id, " => ", doc.data());
        const priceSnap = await doc.ref.collection("prices").get();

        priceSnap.docs.forEach((snap) => {
          data.push({ product: doc.data(), price: snap.data() });
          // console.log(snap.id, " => ", snap.data());
        });
        return res.status(200).json(data);
      });
    })
    .catch((err) => {
      console.log(err);
      res.status(500).json({ error: err.code });
    });
};

Returns this error message: UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client].

The data is returned (only all of it if I refresh the page) but with the error message mentioned above. If I remove this part then it disappears.

 priceSnap.docs.forEach((snap) => {
          data.push({ product: doc.data(), price: snap.data() });
          // console.log(snap.id, " => ", snap.data());
        });

Update

This will get rid of the error message but no data is returned. Same thing if I chain the return res in another .then(). My theory is that the response gets returned before the data is fetched. Any ideas how to solve that?

exports.fetchProducts = (req, res) => {
  let data = [];
  db.collection("products")
  .where("active", "==", true)
  .get()
  .then(function (querySnapshot) {
    querySnapshot.forEach(async function (doc) {
      // console.log(doc.id, " => ", doc.data());
       const priceSnap = await doc.ref.collection("prices").get();

      priceSnap.docs.forEach((snap) => {
       data.push({ product: doc.data(), price: snap.data() });
       // console.log(snap.id, " => ", snap.data());
      });
    });
   return res.status(200).json(data);
})
.catch((err) => {
  console.log(err);
  res.status(500).json({ error: err.code });
});
};

##Solution## I did find a solution to the problem. You can find it in this thread: How to achieve async behavior with nested firebase's forEach?

1 Answer 1

2

After I formatted your code, the answer seemed obvious. You are sending response within your loop, hence sending multiple response which results in UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client].

Get return res.status(200).json(data); out of the loop.

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

3 Comments

Thank you for taking the time to answer. If this is how you meant (and I tried that before too). Then it removes the message but also removes the data ` .then(function (querySnapshot) { let data = []; querySnapshot.forEach(async function (doc) { // console.log(doc.id, " => ", doc.data()); const priceSnap = await doc.ref.collection("prices").get(); priceSnap.docs.forEach((snap) => { data.push({ product: doc.data(), price: snap.data() }); // console.log(snap.id, " => ", snap.data()); }); }); return res.status(200).json(data); })`
declare data out of the loop so you can have access to it when you use res.status(200).json(data)
Thanks for helping out. But if I move it outside then no data will be returned. It seems like the response is sent before the "price" data is fetched. The error message disappeared but so does the data. If I only push the doc.data() from the products collection to the data array. It works if I push it before this line const priceSnap = await doc.ref.collection("prices").get();. If I push it afterwards then nothing gets returned.

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.