Firebase - Node.js - Express - Error [ERR_HTTP_HEADERS_SENT]

Viewed 169

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 Answers

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.

Related