I have below rules set for my firebase collection - payments
"payments": {
"$paymentId": {
"totalAmount": {
},
"balanceAmount": {
".validate": "newData.val()<=data.child('totalAmount').val()"
},
"paymentDetails": {
"$detailId": {
"amount": {
".validate": "newData.isString()"
},
}
},
}
}
and below cloud function written to handle certain updates on that collection:
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);
})
});
Its simple, whenever I add a payment details, I want to update the balanceAmount
. The problem here is, whenever an update occurs at that collection, the function triggers twice. First time its obvious from application and 2nd time its because of paymentRef.set(payment);
line.
Is there any possible way I can avoid this 2nd trigger on cloud function? I cannot use any flag on collection
level since the update on payment details happens multiple times. Can someone guide me in the right direction on this?
EDIT
Note - I've an edit option for payment details entered.
If you want update the balance amount only when you add a payment details you can use the onCreate trigger directly on the payment details.
Try something like that (You have to update the code for your case) :
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
});
});
(Use the transaction to manage concurrent modifications)
Transactions documentation.
NOTE
Please, use directly a Number for your amount data not a String.
UPDATE
Add this function to manage the update :
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
});
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With