获取文档时出错:clientDetails错误:无法修改已提交的WriteBatch

时间:2019-12-04 17:00:14

标签: javascript firebase google-cloud-firestore google-cloud-functions updates

在Firestore批量更新中出现此错误的原因是什么?承诺作为批处理提交返回,并且在循环内创建批处理。我无法解决这个问题。有什么建议吗?

export const updateUserDetailsTypeform = functions.firestore.
  document('responseClientDetails/{case}').onCreate((snap, context) => {

    const newValue = snap.data();
    const caseReference = snap.id;
    var batch = db.batch();

    var reg = "[^£]*£[^£]*";
    const uid = caseReference.match(reg);
    if (uid && newValue) {

      let document = db.collection("responseClientDetails").doc(caseReference);
      let refDoc = db.collection("clientDetails").doc(uid[0])
      batch.update(refDoc,{ has_seen_setup: "true" })


 document.get().then(function (doc: any) {
        if (doc.exists) {
          let refNo = db.collection("clientDetails").doc(uid[0])
          for (let [key, value] of Object.entries(doc.data())) {
            const keyValue = key;
            const valueValue = value;
            batch.update(refNo, { [keyValue]: valueValue })
           // promises.push(db.collection("clientDetails").doc(uid[0]).update({ [keyValue]: valueValue }))
          }

        }else{
          console.log("document does not exist")
        } 
      }).catch(function (error: any) {
        console.log("Error getting document: clientDetails", error);
      });



return batch.commit().then(function () {
  console.log("updated clientDetails")
  return null

});

    }


  });


2 个答案:

答案 0 :(得分:1)

您将必须确保仅在执行所有更新之后调用batch.commit()。您的代码现在正在做的工作是在调​​用第二个更新之前提交。

问题在于get()是异步的,并且在查询完成之前立即返回。如果添加一些日志记录语句,您将更好地了解正在发生的事情。您需要做的是,等到从get()返回的promise完全解析后再提交批处理。这意味着您对batch.commit()的调用可能应该出现在then回调中。

答案 1 :(得分:0)

您对batch.update(refNo, { [keyValue]: valueValue })的呼叫是异步运行的,并且在您对batch.commit的呼叫后会触发

让我们稍微整理一下代码示例,并添加一些注释以帮助说明会发生什么。

// 1 - This fires synchronously
batch.update(db.collection("clientDetails").doc(uid[0]), { has_seen_setup: "true" });

// 2 - This fires synchronously
db.collection("responseClientDetails").doc(caseReference).get().then(function (doc: any) {
  if (doc.exists) {
    let refNo = db.collection("clientDetails").doc(uid[0])
    for (let [key, value] of Object.entries(doc.data())) {
      const keyValue = key;
      const valueValue = value;
      // 4 - This fires asynchronously AFTER #3 runs, therefore the batch has been committed
      batch.update(refNo, { [keyValue]: valueValue })
    }
  } else {
    console.log("document does not exist")
  }
}).catch(function (error: any) {
  console.log("Error getting document: clientDetails", error);
});

// 3 - This fires synchronously
return batch.commit().then(function () {
  console.log("updated clientDetails")
  return null
});

因此,您的解决方法可能是将您的batch.commit通话移至then()通话:

batch.update(db.collection("clientDetails").doc(uid[0]), { has_seen_setup: "true" });

db.collection("responseClientDetails").doc(caseReference).get().then(function (doc: any) {
  if (doc.exists) {
    let refNo = db.collection("clientDetails").doc(uid[0])
    for (let [key, value] of Object.entries(doc.data())) {
      const keyValue = key;
      const valueValue = value;
      batch.update(refNo, { [keyValue]: valueValue })
    }
  } else {
    console.log("document does not exist")
  }
})
.then(() => {
  return batch.commit().then(function () {
    console.log("updated clientDetails")
    return null
  });
})
.catch(function (error: any) {
  console.log("Error getting document: clientDetails", error);
});