Cloud Functions for Firebase OnWrite

14,960

Solution 1

The issue isn't that you can't or shouldn't change the data, but that you need to guard against infinite loops. For instance, setting a timestamp could retrigger the function which would set the timestamp which would retrigger...and so on.

What you can do, however, is guard your code by making sure to mark the state in an idempotent way so the same code doesn't retrigger. For example:

exports.doThing = functions.database.ref('/events/{id}').onWrite(ev => {
  // prevent loops by guarding on data state
  if (ev.data.child('didThingAt').exists()) return;

  // do thing here...

  return ev.data.adminRef.update({
    didThingAt: admin.database.ServerValue.TIMESTAMP
  });
});

Solution 2

I understand firebase functions provides a better method:

The method is to verify if a previous event exists. If so, do nothing and return else, do you job... Besides you can verify if item is being deleted.

  if (event.data.previous.exists()) {
    return;
  }
  // Exit when the data is deleted.
  if (!event.data.exists()) {
    return;
  }

This is full example from firebase documentation.

exports.makeUppercase = functions.database.ref('/messages/{pushId}/original')
    .onWrite(event => {
      // Only edit data when it is first created.
      if (event.data.previous.exists()) {
        return;
      }
      // Exit when the data is deleted.
      if (!event.data.exists()) {
        return;
      }
// Grab the current value of what was written to the Realtime Database.
const original = event.data.val();
console.log('Uppercasing', event.params.pushId, original);
const uppercase = original.toUpperCase();
// You must return a Promise when performing asynchronous tasks inside a Functions such as
// writing to the Firebase Realtime Database.
// Setting an "uppercase" sibling in the Realtime Database returns a Promise.
return event.data.ref.parent.child('uppercase').set(uppercase);
Share:
14,960

Related videos on Youtube

Mark
Author by

Mark

Updated on August 24, 2022

Comments

  • Mark
    Mark over 1 year

    I'm looking at the New Cloud Functions for Firebase and it says when doing an OnWrite you should be careful not to save data back to the same Child. (which will fire off the trigger again).

    So I'm trying to figure out, how do I set a modification date on a record ?

    • Mark
      Mark about 7 years
      Thats really only an example... I don't want a solution on how to set a modification date. I want a solution on how I can change data serverside.
    • Mark
      Mark about 7 years
      Lets say, the client changes data and I need to process a financial transaction and then delete the record. A delete is a change to OnWrite so I'm not sure how to organise that code.
  • Mark
    Mark about 7 years
    Cheers That Helps
  • Mark
    Mark about 7 years
    Thats the example which caused the question. It doesn't solve the problem because if you write back to record, then event.data.previous.exists() actually exists from the first parse of the write function.
  • TheBen
    TheBen about 7 years
    Sorry, could someone explain a little what this does? I know generally why we would need to do such a thing but this code is not entirely clear to me. My poor skills
  • Michael Bleigh
    Michael Bleigh about 7 years
    This is writing a new value to the location with key didThingAt. When the function triggers, it is checking if the didThingAt field already exists, and simple stops executing if it did. In between those two statements you would perform the "only once" logic.
  • edhnb
    edhnb about 7 years
    If a field is updated/incremented many times (for example, incrementing a counter each time an action is taken), is there a way to have the function increment that field only once, and recognize that the field was updated and not execute again? The only thing I can think is to have the function .onWrite event on a different table reference.. and call another function to update the table containing the incrementing field separately.
  • DarkNeuron
    DarkNeuron about 7 years
    Wish there was a way to suppress this from triggering, when invoking writes from cloud functions.
  • Ali SadeghipourKorabaslo
    Ali SadeghipourKorabaslo about 6 years
    @Michael Bleigh is it possible to use triggers for all requests in expressjs?
  • Jesús Fuentes
    Jesús Fuentes almost 6 years
    What if didThingAt already exists but because it's an actual modification of the document you want to update the field? It will still go into a loop.