1

I am trying to send a notification to "PLAYER 2" when a new game is added. Here is my code:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);


exports.sendNewGameNotification= functions.database.ref('/GAMES/{gameId}/PLAYER 2').onWrite(event => {
const player2uid = event.params.val;

const getDeviceTokensPromise = admin.database().ref(`/USERS/${player2uid}/fcm`).once('value');

return Promise.all([getDeviceTokensPromise]).then(results => {

const tokensSnapshot = results[0];
// Notification details.
const payload = {
  'data': { 
        'title': "Tienes una nueva partida"
  }
};

// Listing all tokens, error here below.
const tokens = Object.keys(tokensSnapshot.val());

// Send notifications to all tokens.
return admin.messaging().sendToDevice(tokens, payload).then(response => {
  // For each message check if there was an error.
  const tokensToRemove = [];
  response.results.forEach((result, index) => {
    const error = result.error;
    if (error) {
      console.error('Failure sending notification to', tokens[index], error);
      // Cleanup the tokens who are not registered anymore.
      if (error.code === 'messaging/invalid-registration-token' ||
          error.code === 'messaging/registration-token-not-registered') {
        tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove());
      }
    }
  });
  return Promise.all(tokensToRemove);
});
});
});

When it is executed, in the firebase console says

 TypeError: Cannot convert undefined or null to object

Like if it were null but the fcm is there, what am i doing wrong?

1 Answer 1

3

I think instead of this:

const player2uid = event.params.val;

you want this:

const player2uid = event.data.val();

Edit:

This update to your code contains some added checks and a simplification. This works for me.

The database structure for storing the token (or tokens) is critical. The tokens are the keys, not the values. The values are not significant and can be simple placeholders, such as booleans.

For example:

  "USERS" : {
    "Roberto" : {
      "fcm" : {
        "eBUDkvnsvtA:APA...rKe4T8n" : true
      }
    },
    "Juan" : {
      "fcm" : {
        "fTY4wvnsvtA:APA91bGZMtLY6R...09yTLHdP-OqaxMA" : true
      }
    }
  }

.

exports.sendNewGameNotification= functions.database.ref('/GAMES/{gameId}/PLAYER 2').onWrite(event => {
const player2uid = event.data.val();

return admin.database().ref(`/USERS/${player2uid}`).once('value').then(snapshot => {
   if (!snapshot.exists()) {
        console.log('Player not found:', player2uid);
        return;
    }
    const tokensSnapshot = snapshot.child('fcm');
    if (!tokensSnapshot.exists()) {
        console.log('No tokens for player: ', player2uid);
        return;
    }

    // Notification details.
    const payload = {
      'data': {
            'title': "Tienes una nueva partida"
      }
    };

    // Listing all tokens, error here below.
    const tokens = Object.keys(tokensSnapshot.val());

    // Send notifications to all tokens.
    return admin.messaging().sendToDevice(tokens, payload).then(response => {
      // For each message check if there was an error.
      const tokensToRemove = [];
      response.results.forEach((result, index) => {
        const error = result.error;
        if (error) {
          console.error('Failure sending notification to', tokens[index], error);
          // Cleanup the tokens who are not registered anymore.
          if (error.code === 'messaging/invalid-registration-token' ||
              error.code === 'messaging/registration-token-not-registered') {
              tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove());
          }
        }
      });
      return Promise.all(tokensToRemove);
});
});
});
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks man, that is solved but now it throws me Error: Invalid registration token provided. Make sure it matches the registration token the client app receives from registering with FCM any idea why?
Are you storing one token under /USERS/${player2uid}/fcm or multiple?
I am storing just one
How did you fix it?
Oh man, thank you for pointing out that the tokens had to be put in the database as keys! You saved me hours of banging my head against the wall.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.