Firebase Cloud 函数触发两次 onUpdate
Firebase Cloud function triggers twice onUpdate
我为 firebase collection - payments
设置了以下规则
"payments": {
"$paymentId": {
"totalAmount": {
},
"balanceAmount": {
".validate": "newData.val()<=data.child('totalAmount').val()"
},
"paymentDetails": {
"$detailId": {
"amount": {
".validate": "newData.isString()"
},
}
},
}
}
及以下为处理该集合的某些更新而编写的云函数:
exports.calculateBalance = functions.database
.ref('payments/{pushId}')
.onUpdate(event => {
const paymentRef = event.data.adminRef;
const payment = event.data.val();
return paymentRef.once('value').then(snapshot => {
var paidAmount = 0;
snapshot.child("paymentDetails").forEach(function(child) {
paidAmount += parseFloat(child.child("amount").val());
});
return paidAmount;
}).then(snap => {
payment.balanceAmount = parseFloat(payment.totalAmount) - snap;
return paymentRef.set(payment);
})
});
很简单,每当我添加付款明细时,我都想更新 balanceAmount
。这里的问题是,每当该集合发生更新时,该函数都会触发 两次 。第一次从应用程序中很明显,第二次是因为 paymentRef.set(payment);
行。
有什么方法可以避免第二次触发云功能?我不能在 collection
级别上使用任何标志,因为付款详细信息更新发生多次。有人可以指导我正确的方向吗?
编辑
注意 - 我有一个用于输入付款详细信息的编辑选项。
如果您只想在添加付款明细时更新余额,您可以直接在付款明细上使用onCreate触发器.
尝试类似的方法(您必须为您的案例更新代码):
exports.calculateBalance = functions.database.ref('payments/{pushId}/paymentDetails/{detailId}').onCreate(event => {
var paymentRef = event.data.adminRef.parent.parent;
var paymentDetailSnapshot = event.data;
var paymentDetailAmountSnapshot = paymentDetailSnapshot.child('amount');
return paymentRef.child('balanceAmount').transaction(current => {
return current - paymentDetailAmountSnapshot.val(); // Balance can be negative
});
});
(使用事务管理并发修改)
注意
请直接使用 Number 作为您的 金额数据 而不是 String。
更新
添加此功能来管理更新:
exports.recalculateBalance = functions.database.ref('payments/{pushId}/paymentDetails/{detailId}').onUpdate(event => {
var paymentRef = event.data.adminRef.parent.parent;
var paymentDetailSnapshot = event.data;
var previousPaymentDetailSnapshot = event.data.previous;
var paymentDetailAmountSnapshot = paymentDetailSnapshot.child('amount');
var previousPaymentDetailAmountSnapshot = previousPaymentDetailSnapshot.child('amount');
return paymentRef.child('balanceAmount').transaction(current => {
return current + previousPaymentDetailAmountSnapshot.val() - paymentDetailAmountSnapshot.val(); // Balance can be negative
});
});
我为 firebase collection - payments
"payments": {
"$paymentId": {
"totalAmount": {
},
"balanceAmount": {
".validate": "newData.val()<=data.child('totalAmount').val()"
},
"paymentDetails": {
"$detailId": {
"amount": {
".validate": "newData.isString()"
},
}
},
}
}
及以下为处理该集合的某些更新而编写的云函数:
exports.calculateBalance = functions.database
.ref('payments/{pushId}')
.onUpdate(event => {
const paymentRef = event.data.adminRef;
const payment = event.data.val();
return paymentRef.once('value').then(snapshot => {
var paidAmount = 0;
snapshot.child("paymentDetails").forEach(function(child) {
paidAmount += parseFloat(child.child("amount").val());
});
return paidAmount;
}).then(snap => {
payment.balanceAmount = parseFloat(payment.totalAmount) - snap;
return paymentRef.set(payment);
})
});
很简单,每当我添加付款明细时,我都想更新 balanceAmount
。这里的问题是,每当该集合发生更新时,该函数都会触发 两次 。第一次从应用程序中很明显,第二次是因为 paymentRef.set(payment);
行。
有什么方法可以避免第二次触发云功能?我不能在 collection
级别上使用任何标志,因为付款详细信息更新发生多次。有人可以指导我正确的方向吗?
编辑
注意 - 我有一个用于输入付款详细信息的编辑选项。
如果您只想在添加付款明细时更新余额,您可以直接在付款明细上使用onCreate触发器.
尝试类似的方法(您必须为您的案例更新代码):
exports.calculateBalance = functions.database.ref('payments/{pushId}/paymentDetails/{detailId}').onCreate(event => {
var paymentRef = event.data.adminRef.parent.parent;
var paymentDetailSnapshot = event.data;
var paymentDetailAmountSnapshot = paymentDetailSnapshot.child('amount');
return paymentRef.child('balanceAmount').transaction(current => {
return current - paymentDetailAmountSnapshot.val(); // Balance can be negative
});
});
(使用事务管理并发修改)
注意
请直接使用 Number 作为您的 金额数据 而不是 String。
更新
添加此功能来管理更新:
exports.recalculateBalance = functions.database.ref('payments/{pushId}/paymentDetails/{detailId}').onUpdate(event => {
var paymentRef = event.data.adminRef.parent.parent;
var paymentDetailSnapshot = event.data;
var previousPaymentDetailSnapshot = event.data.previous;
var paymentDetailAmountSnapshot = paymentDetailSnapshot.child('amount');
var previousPaymentDetailAmountSnapshot = previousPaymentDetailSnapshot.child('amount');
return paymentRef.child('balanceAmount').transaction(current => {
return current + previousPaymentDetailAmountSnapshot.val() - paymentDetailAmountSnapshot.val(); // Balance can be negative
});
});