在 firebase admin 中交易后设置新文档

Set new document after transaction in firebase admin

我正在创建一个 API 检查计数器值,递增 1,然后在文档集合中创建新文档。为此,我使用 runTransaction().

我 运行 遇到了问题。交易按预期工作,检查计数器值,然后将其递增 1。但在那之后,当我尝试设置新文档时,出现错误(空对象),我无法这样做。我认为我使用的逻辑可能不好,所以我需要你的建议。

const db = admin.firestore()

const couterRef = db.collection('invoices').doc('invoices_doc')

let counterValue = 0

    // check last invoice counter number and increment by 1
    return db.runTransaction((transaction) => {
      return transaction
        .get(couterRef)
        .then((counter) => {
          counterValue = counter.data().counter + 1
          // Update counter
          return transaction.update(couterRef, { counter: counterValue })
        })
        .catch((error) => response.status(200).send({ status: 'TRANSACTION ERROR', error }))
    })
      .then(() => {
        // Create new invoice document
        couterRef.collection('invoices').doc(counterValue).set({
           series: 'SS',
           series_nr: counterValue
        })
        .then(() => response.status(200).send({ status: 'OK' }))
        .catch((error) => response.status(200).send({ status: 'DOCUMENT SET ERROR', error }))
      })
      .catch((error) => {
        response.status(200).send({ status: 'RUN TRANSACTION ERROR', error })
      })

我没有测试过您的代码,但问题很可能是因为 您在交易函数中修改了应用程序状态,这是您必须避免的事情。文档中有关于此问题的specific section

您需要将counterValue的新值传出您的交易函数,如下:

  const db = admin.firestore();
  const couterRef = db.collection('invoices').doc('invoices_doc');

  // let counterValue = 0  Remove this line

  return db
    .runTransaction((transaction) => {
      return transaction.get(couterRef).then((counter) => {
        const counterValue = counter.data().counter + 1;
          // See the changes below !!
        transaction.update(couterRef, { counter: counterValue });  // Actually, this in not an asynchronous operation
        return counterValue;  // We pass the new value of counterValue out of the transaction function
      });
    })
    .then((counterValue) => {
      // Create new invoice document
      couterRef.collection('invoices').doc(counterValue.toString(10)).set({
        series: 'SS',   // you missed a ,
        series_nr: counterValue,
      });
    })
    .then(() => response.status(200).send({ status: 'OK' }))
    .catch((error) => {
      response.status(200).send({ status: 'RUN TRANSACTION ERROR', error });
    });

此外,在您的 HTTPS 云函数中,不要从事务内将响应发送回客户端:这也是应用程序状态修改,不应从事务内完成。

同样,不要在then块中包含catch块:在catch块的末尾添加一个仅一次 promise chain。如果您想在这个独特的 catch 块中处理不同的错误类型,只需抛出带有不同错误消息的错误,然后在 catch 块中根据消息决定要做什么。或者,您可以创建错误 class.

的一些子 classes

综上所述,由于您的事务只影响一个文档并且只增加一个计数器,因此您可以使用 FieldValue.increment() method, which is atomic. See this Firebase blog post 了解更多详细信息。