假设我有一个updateLog()
函数,它执行以下操作:
只是一个伪:
const updateLog = (logData) => {
return db.runTransaction( t => {
return t.get(logRef)
.then(log => {
if (!log.exists) {
// blah blah blah
} else {
// blah blah blah
}
}
}
}
但我还有另一个函数,即可以是事务的发起者,而updateLog()
函数只能是事务的部分。
const createDoc = (docData) => {
return db.runTransaction( t => {
t.set(docRef, docData);
// Here, the updateLog() can only be part of the transaction.
return updateLog(docData, t???)
.then(result => {
if (!result) {
// blah blah blah
} else {
// blah blah blah
}
}
}
}
问题:,所以在我的updateLog()
中,我是否可以接受transaction
作为一个可选参数,同时仍然保留它作为独立事务发起者的能力?因此,如何为updateLog()
创建一个可选参数,使runTransaction
到(可选地)接受它作为事务的一部分?我之所以要这样做,是因为我希望避免重复runTransaction
块中的逻辑,或者编写另一个管理事务可用性的“代理”或“路由器”。任何建议都将不胜感激,谢谢!
const updateLog = (logData, transaction = null) => {
// How do I pass transaction as t in this context?
// Possible?
return db.runTransaction( t => {
return t.get(logRef)
.then(log => {
if (!log.exists) {
// blah blah blah
} else {
// blah blah blah
}
}
}
}
发布于 2020-10-24 16:44:49
在等待了一个多星期的答复后,显然我们不可能有条件地await firestore.runTransaction()
如下:
const updateLog = async (logData, transaction = null) => {
if (!transaction) {
transaction = await firestore.runTransaction();
};
// Start manipulating data here.
}
您不能等待事务完成并在 runTransaction
之外执行数据操作任务--这是完全违背了事务的目的。
解决方案:预测不可预测的
提供成为事务的独立和部分的灵活性的最佳方法是,在任何runTransaction
直接数据操作函数中,不是 to ,而是最外层的调用方,例如Firebase函数:
data-layer.js
const updateLog = (logData, transaction) => {
if (!transaction || transaction instanceof admin.firestore.Transaction === false) {
throw new Error(`Invalid argument: transaction. It must be an instance of Firestore Transaction.`);
};
// Assuming logRef has been created here.
return transaction.get(logRef)
.then(log => {
if (!log.exists) {
// blah blah blah
} else {
// blah blah blah
}
}
}
const createDoc = (docData, transaction) => {
if (!transaction || transaction instanceof admin.firestore.Transaction === false) {
throw new Error(`Invalid argument: transaction. It must be an instance of Firestore Transaction.`);
};
// Assuming docRef has been created here.
transaction.set(docRef, docData);
// Here, the updateLog() can be part of the transaction.
return updateLog(docData, transaction)
.then(result => {
if (!result) {
// blah blah blah
} else {
// blah blah blah
}
}
}
[消]火基函数
"use strict";
const admin = require("firebase-admin");
exports.createDoc = functions.https.onCall((data, context) => {
const firestore = admin.firestore();
// Transaction will only be initiated as needed
// by the caller.
return firestore.runTransaction(transaction => {
return createDoc(data.docData, transaction)
.then(result => {
// Log has also been updated when running createDoc()
return result;
}
}.catch(error => {
throw new functions.https.HttpsError("failed-precondition", `${error.message}`);
};
});
exports.updateLog = functions.https.onCall((data, context) => {
const firestore = admin.firestore();
// The updateLog() now can also be standalone.
return firestore.runTransaction(transaction => {
return updateLog(data.logData, transaction)
.then(result => {
// Log has been updated.
return result;
}
}.catch(error => {
throw new functions.https.HttpsError("failed-precondition", `${error.message}`);
};
});
结论:
让每个较小的数据服务函数接受transaction
参数,并在打包为一个完整的任务时启动runTransaction
only ,这是一个很好的实践。这应该是相对安全的,特别是当首先验证所需的transaction
参数时,同时能够在使用数据服务时提供更大的灵活性。
https://stackoverflow.com/questions/64369907
复制相似问题