0
votes

I have three Firebase database trigger function to push notifications to users. However, I have noticed that .onCreate() gets triggered on database update and delete. Is this expected? Is there a way to prevent this?

const functions = require('firebase-functions')

exports.onNoteCreate = functions
.region('europe-west1')
.database
.ref('/notes/{noteId}')
.onCreate((snapshot, context) => {
  ...
  //Push notification to affected users

  //Compose notification object
  const notificationObject = { "test": true }
  membersToAlert.forEach((memberId, index) => {
    let isAlreadyPresent = false
    //Do not write if already present! - This code should not be needed?
    const ref = snapshot.ref.root.child(`/notes/${personId}/noteAdditions`)
    ref.orderByChild('originId')
      .equalTo(noteId)
      .on("value", (removeSnapshot) => {
        isAlreadyPresent = true
      })
    //Write notification to all affected users
    if(!isAlreadyPresent) {
      snapshot.ref.root.child(`/notifications/${personId}/noteAdditions`).push(notificationObject)
    }
  })
  return true
})

My .onUpdate() and .onDelete() triggers are also listening to .ref('/notes/{noteId}'). Is that a problem?

How can I make sure .onCreate() only gets triggered when a new object is inserted?

EDIT:

My testing workflow is as follows:

  1. Create a new node in /notes using .push() -> works as expected

  2. Update the same node using .update() -> works as expected

  3. Delete the node in /notes/{noteId} directly from the Firebase Console

Step 3 triggers both .onCreate() and .onUpdate(). See log below:

I 2019-08-12T17:17:25.867Z onNoteCreate 670055884755913 onNoteCreate ... onNoteCreate 670055884755913 
I 2019-08-12T17:17:26.053Z onNoteUpdate 670048941917608 onNoteUpdate ... onNoteUpdate 670048941917608 
D 2019-08-12T17:17:26.843878505Z onNoteDelete 670054292162841 Function execution started onNoteDelete 670054292162841 
D 2019-08-12T17:17:26.849773576Z onNoteDelete 670054292162841 Function execution took 7 ms, finished with status: 'ok' onNoteDelete 670054292162841

Database before delete

-notifications
  -userId
    -noteAdditions
      -guid01
        -notificationData
    -noteUpdates
      -guid03
        -notificationData

Database after delete

//guid01 gets deleted by .onDelete() as expected
//guid03 gets deleted by .onDelete() as expected

-notifications
  -userId
    -noteAdditions
      -guid02
        -notificationData //Inserted by .onCreate() upon delete
    -noteUpdates
      -guid04
        -notificationData //Inserted by .onUpdate() upon delete

The listeners are attached to /notes/{noteId} and updates are being made at /notifications/{userId}/...

onNoteCreate

exports.onNoteCreate = functions
.region('europe-west1')
.database
.ref('/notes/{noteId}')
.onCreate((snapshot, context) => {
  ...
  snapshot.ref.root.child(`/notifications/${personId}/noteAdditions`).push(notificationObject)
  ...
  console.log('onNoteCreate', '...')
  ...
})

onNoteUpdate

exports.onNoteUpdate = functions
.region('europe-west1')
.database
.ref('/notes/{noteId}')
.onUpdate((change, context) => {
  ...
  change.after.ref.root.child(`/notifications/${personId}/noteUpdates`).push(notificationObject)
  ...
  console.log('onNoteUpdate', '...')
  ...
})

Does it matter that I import the functions like so?

const create = require('./src/db-functions/notes').onNoteCreate
const update = require('./src/db-functions/notes').onNoteUpdate
const delete = require('./src/db-functions/notes').onNoteDelete
exports.onNoteCreate = create
exports.onNoteUpdate = update
exports.onNoteDelete = delete
1
onCreate should not fire when an existing node matched by {nodeId} is modified. Could you edit the question to provide more information about exactly what you're doing that causes this function to run when you think it should not. Please be specific about any other code that makes changes, or manual actions you're taking, making sure to illustrate the before and after state of the database. - Doug Stevenson
Hi @Doug ! Thanks for the prompt reply! .onUpdate() works as expected - onDelete that causes the problem. I will add more information to better describe the behaviour. - Kermit
I don't see the lines of code that log the statements that you see as problematic. I see a one line of code in the log that comes from the system that suggests that only onNoteDelete gets invoked and no similar log for onNoteCreate. - Doug Stevenson
I delete the record in the Firebase Console @ 2019-08-12T17:17:25.867Z. I have added pseudo code for onNoteCreate and onNoteUpdate. - Kermit
Clarification: oNoteCreate & onNoteUpdate gets triggered first when I perform a delete - lastly onNoteDelete :-/ - Kermit

1 Answers

0
votes

I failed to include the code in my example where I call

  //Get user data - also updated by onNoteCreate, onNoteUpdate , onNoteDelete
  dbRoot.child(`users/${userId}`)
  .on('value', (snapshot) => {

.on() attached a listener that was being triggered each time the value was updated, thus triggering "onNoteCreate", "onNoteUpdate" and "onNoteDelete" when not expected. I should have used .once() if I did not wish to attach a listener which I did not.

All credits to @doug for pointing this out to me in this post: Firebase database trigger - how to wait for calls