Firebase函数接收对象而不是字符串

时间:2019-09-13 00:31:03

标签: android firebase firebase-realtime-database firebase-cloud-messaging

与我同在。我花了一个月的时间回答这个问题:我已经使用Firebase数据库和Firebase函数大约一年了。我已经开始使用它了……但是只有当我以STRING的形式发送消息时,才可以使用它。问题是现在我希望接收一个对象,但是我不确定如何在FireBaseMessage中执行此操作。

我以前的结构:

messages
   T9Vh5cvUcbqC8IEZowBpJC3
      ZWfn7876876ZGJeSNBbCpPmkm1
           message



"messages": {
        ".read": true,
      "$receiverUid": {
        "$senderUid": {
          "$message": {
            ".read": true,
            ".write": "auth.uid === $senderUid"

我对侦听器的功能是:

exports.sendMessage = functions.database.ref('/messages/{receiverUid}/{senderUid}/{message}')

这是有问题的...出于多种原因。即,如果旧消息是“ Hey”,然后同一个人再次写“ Hey” ...,则原始消息将被覆盖。

所以我的NEW结构更像这样:

messages
  -LkVcYqJoEroWpkXZnqr
      body: "genius grant"
      createdat: 1563915599253
      name: "hatemustdie"
      receiverUid: "TW8289372984KJjkhdsjkhad"
      senderUid: "yBNbs9823789KJkjahsdjkas"

写为:

mDatabase.child("messages").push().setValue(message);

...我只是不确定如何编写该函数。

我的意思是……真的……应该是这样的:

exports.sendMessage = functions.database.ref('/messages/{receiverUid}/{senderUid}/{msgID}/{msgOBJECT}')

...但是我只是不确定Firebase的功能如何读取这种新结构。

现在,我将像这样推送到数据库:

mDatabase.child("messages").child(guid).child(user_Id).push().setValue(msgObject).addOnSuccessListener(this, new OnSuccessListener<Void>() {
                                @Override
                                public void onSuccess(@NonNull Void T) {
                                    Log.d("MessageActivity", "Message Sent");

基本上,我只想接收消息对象……包含其中的所有内容……当它从通知到达时……并能够轻松地解析正文,日期,用户ID等。

有人可以解释解决此问题的正确方法吗?

UPATE (按要求)是完整的云功能:

exports.sendMessage = functions.database.ref('/messages/{receiverUid}/{senderUid}/{msgId}/{message}')
    .onWrite(async (change, context) => {
      const message = context.params.message;
      // const messageId = context.params.messageId;
      const receiverUid = context.params.receiverUid;
      const senderUid = context.params.senderUid;
      // If un-follow we exit the function.
      if (!change.after.val()) {
        return console.log('Sender ', senderUid, 'receiver ', receiverUid, 'message ', message);
      }
      console.log('We have a new message: ', message, 'for: ', receiverUid);

      // Get the list of device notification tokens.
      const getDeviceTokensPromise = admin.database()
          .ref(`/users/${receiverUid}/notificationTokens`).once('value');

      // Get the follower profile.
      const getSenderProfilePromise = admin.auth().getUser(senderUid);

      // The snapshot to the user's tokens.
      let tokensSnapshot;

      // The array containing all the user's tokens.
      let tokens;

      const results = await Promise.all([getDeviceTokensPromise, getSenderProfilePromise]);
      tokensSnapshot = results[0];
      const sender = results[1];

        // Check if there are any device tokens.
        if (!tokensSnapshot.hasChildren()) {
          return console.log('There are no notification tokens to send to.');
        }
        console.log('There are', tokensSnapshot.numChildren(), 'tokens to send notifications to.');
        console.log('Fetched sender profile', sender);
//        console.log('David you're looking for the following UID:', followerUid);

        // Notification details.
        const payload = {
          notification: {
            title: `${sender.displayName} sent you a message.`,
            body: message,
            tag: senderUid
          },
        //  'data': { 'fuid': followerUid }
          data: { 
            type: 'message', 
            name: sender.displayName
          }
        };
      console.log('David you are looking for the following message:', message);
        // Listing all tokens as an array.
      tokens = Object.keys(tokensSnapshot.val());
      // Send notifications to all tokens.
      const response = await admin.messaging().sendToDevice(tokens, payload);
      // 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);
  });

2 个答案:

答案 0 :(得分:2)

由于您现在将发送方和接收方的UID存储在消息中,因此需要更改您的Cloud Function的声明。

代替此:

exports.sendMessage = functions.database.ref('/messages/{receiverUid}/{senderUid}/{msgId}/{message}').onWrite(async (change, context) => {

您需要触发以下内容:

exports.sendMessage = functions.database.ref('/messages/{messageId}').onWrite(async (change, context) => {

因此,通过此更改,您的代码将在每条写入/messages的消息上触发。

现在,您“只是”需要获取发送者和接收者的UID。而且,由于您不再可以从context获取它们,因此您将从change获取它们。具体来说,change.after包含数据快照,该快照在写入完成后 中存在于数据库中。因此(只要您不删除数据),就可以通过以下方式获取UID:

const receiverUid = change.after.val().receiverUid;
const senderUid = change.after.val().senderUid;

当然,您还将从那里获得实际的消息:

const message = change.after.val().message;

以防万一,您需要消息ID(在数据库中写入该消息的-L...密钥):

const messageId = change.after.val().messageId;

答案 1 :(得分:1)

您只需要在messageId上触发:

exports.sendMessage = functions.database.ref('/messages/{messageId}').onWrite((change, context) => {
      const changedData = change.after.val(); // This will have the complete changed data
      const message = change.after.val().message;  // This will contain the message value
      ......
});

阐述弗兰克的答案: 您无法从const message = context.params.message;之类的上下文中获取数据,因为这些参数在上下文中已不存在。