5
votes

Is it possible to send the notification from within the app instead of a cloud function on firebase? The reason is, I want to do something similar to: FCM Push Notifications for Flutter, where they have this function that will be deployed to firebase:

export const sendToTopic = functions.firestore
  .document('puppies/{puppyId}')
  .onCreate(async snapshot => {
    const puppy = snapshot.data();

    const payload: admin.messaging.MessagingPayload = {
      notification: {
        title: 'New Puppy!',
        body: `${puppy.name} is ready for adoption`,
        icon: 'your-icon-url',
        click_action: 'FLUTTER_NOTIFICATION_CLICK' // required only for onResume or onLaunch callbacks
      }
    };

    return fcm.sendToTopic('puppies', payload);
  });

this method works as intended on firebase cloud functions, however I need the path

.document('puppies/{puppyId}')

to be dynamic depending on which chatroom a user is in, so he would get a notification everytime i new message is send, so the 'chatroom22' would be a variable:

.document('chatroom22/{roomId}')

So is it possible to do this in the app-code, or can this be done in the deployed function?

In response to Doug Stevensons answer

Okay, that makes sence, and works. However, now everybody get the notifications. I want only the people in a given chatroom to receive the notification. I've tried something like this, where the users device token is saved for a given chat-room, then I want to notiffy all those tokens:

const functions = require('firebase-functions');
const admin = require('firebase-admin');

admin.initializeApp(functions.config().functions);

var newData;
exports.myTrigger = functions.firestore.document('messages/{messageId}/room/{roomId}/message/{messageId2}').onCreate(async (snapshot, context) => {
    //

    if (snapshot.empty) {
        console.log('No Devices');
        return;
    }

    newData = snapshot.data();

    const deviceIdTokens = await admin
        .firestore()
        .collection('messages/{messageId}/room/{roomId}/tokens/{tokenId}')
        .get();

    var tokens = [];

    for (var token of deviceIdTokens.docs) {
        tokens.push(token.data().device_token);
    }
    var payload = {
        notification: {
            title: `${newData.sender}`,
            body: `${newData.message}`,
            sound: 'default',
        },
        data: {
            push_key: 'Push Key Value',
            key1: newData.message,
        },
    };

    try {
        const response = await admin.messaging().sendToDevice(tokens, payload);
        console.log('Notification sent successfully');
    } catch (err) {
        console.log(err);
    }
});

But it doesnt seem to work with wildcards.. how can I get the specific destination for each chatroom?

1

1 Answers

0
votes

You can use a wildcard for the collection in the path:

functions.firestore.document('{collectionId}/{documentId}')

But this will trigger for all documents in all top-level collecitons, which is probably not what you want.

In fact, using variable names for top-level collections is actually not the preferred way to model data in Firestore. Consider instead having a top-level collection for all rooms, then use subcollections to contain their messages. If you do that, then you function becomes more more clearly defined as:

functions.firestore.document('rooms/{roomId}/messages/{messageId}')

Cloud Fuctions only allows wildcards for full path segments like this. There are no other patterns or regular expressions.