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