I'm trying to perform a fetch request within a transaction but when the code executes I receive the following error.
Error: Cannot modify a WriteBatch that has been committed.
The steps the function is performing are the following:
- Compute document references (taken from an external source)
- Query the documents available in Firestore
- Verify if document exists
- Fetch for further details (lazy loading mechanism)
- Start populating first level collection
- Start populating second level collection
Below the code I'm using.
await firestore.runTransaction(async (transaction) => {
  // 1. Compute document references
  const docRefs = computeDocRefs(colName, itemsDict);
  // 2. Query the documents available in Firestore
  const snapshots = await transaction.getAll(...docRefs);
  snapshots.forEach(async (snapshot) => {
    // 3. Verify if document exists
    if (!snapshot.exists) {
      console.log(snapshot.id + " does not exists");
      const item = itemsDict[snapshot.id];
      if (item) {
        // 4. Fetch for further details
        const response = await fetchData(item.detailUrl);
        const detailItemsDict = prepareDetailPageData(response);
        // 5. Start populating first level collection
        transaction.set(snapshot.ref, {
          index: item.index,
          detailUrl: item.detailUrl,
          title: item.title,
        });
        // 6. Start populating second level collection
        const subColRef = colRef.doc(snapshot.id).collection(subColName);
        detailItemsDict.detailItems.forEach((detailItem) => {
          const subColDocRef = subColRef.doc();
          transaction.set(subColDocRef, {
            title: detailItem.title,
            pdfUrl: detailItem.pdfUrl,
          });
        });
      }
    } else {
      console.log(snapshot.id + " exists");
    }
  });
});
computeDocRefs is described below
function computeDocRefs(colName, itemsDict) {
  const identifiers = Object.keys(itemsDict);
  const docRefs = identifiers.map((identifier) => {
    const docId = `${colName}/${identifier}`
    return firestore.doc(docId);
  });
  return docRefs;
}
while fetchData uses axios under the hood
async function fetchData(url) {
  const response = await axios(url);
  if (response.status !== 200) {
    throw new Error('Fetched data failed!');
  }
  return response;
}
prepareMainPageData and prepareDetailPageData are functions that prepare the data normalizing them.
If I comment the await fetchData(item.detailUrl), the first level collection with all the documents associated to it are stored correctly.
On the contrary with await fetchData(item.detailUrl) the errors happens below the following comment: // 5. Start populating first level collection.
The order of the operation are important since I do now want to make the second call if not necessary.
Are you able to guide me towards the correct solution?
