问题
When writing event based cloud functions for firebase firestore it's common to update fields in the affected document, for example:
When a document of users collection is updated a function will trigger, let's say we want to determine the user info state and we have a completeInfo: boolean
property, the function will have to perform another update so that the trigger will fire again, if we don't use a flag like needsUpdate: boolean
to determine if excecuting the function we will have an infinite loop.
Is there any other way to approach this behavior? Or the situation is a consequence of how the database is designed? How could we avoid ending up in such scenario?
回答1:
I have a few common approaches to Cloud Functions that transform the data:
Write the transformed data to a different document than the one that triggers the Cloud Function. This is by far the easier approach, since there is no additional code needed - and thus I can't make any mistakes in it. It also means there is no additional trigger, so you're not paying for that extra invocation.
Use granular triggers to ensure my Cloud Function only gets called when it needs to actually do some work. For example, many of my functions only need to run when the document gets created, so by using an
onCreate
trigger I ensure my code only gets run once, even if it then ends up updating the newly created document.Write the transformed data into the existing document. In that case I make sure to have the checks for whether the transformation is needed in place before I write the actual code for the transformation. I prefer to not add flag fields, but use the existing data for this check.
A recent example is where I update an amount in a document, which then needs to be fanned out to all users:
exports.fanoutAmount = functions.firestore.document('users/{uid}').onWrite((change, context) => { let old_amount = change.before && change.before.data() && change.before.data().amount ? change.before.data().amount : 0; let new_amount = change.after.data().amount; if (old_amount !== new_amount) { // TODO: fan out to all documents in the collection } });
回答2:
You need to take care to avoid writing a function that triggers itself infinitely. This is not something that Cloud Functions can do for you. Typically you do this by checking within your function if the work was previously done for the document that was modified in a previous invocation. There are several ways to do this, and you will have to implement something that meets your specific use case.
回答3:
I would take this approach from an execution time perspective, this means that the function for each document will be run twice. Each time when the document is triggered, a field lastUpdate
would be there with a timestamp and the function only updates the document if the time is older than my time - eg 10 seconds.
来源:https://stackoverflow.com/questions/55887753/how-to-avoid-loops-when-writing-cloud-functions