Преобразование облачной функции базы данных в реальном времени в Firestore - PullRequest
0 голосов
/ 11 апреля 2019

Я следую этому примеру в файле node.js, чтобы отправить уведомление в мое мобильное приложение и удалить все токены, которые не используются пользователем, из массива в документе в Firestore. Изначально мой исходный код предполагал, что у каждого пользователя есть только один токен. После нескольких дней ошибок я определил, как управлять несколькими токенами пользователя как в облаке, так и в моем коде Android. (https://github.com/firebase/functions-samples/blob/master/fcm-notifications/functions/index.js)

Ниже приведен мой исходный код node.js, который я использую для связи с помощью одного токена.

'use-strict'

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

exports.sendAcceptFriendRequest=functions.firestore.document("Notifications/{user_id}/Accepted_Friend_Requests/{user_email}").onWrite((change,context)=> {
    const user_id=context.params.user_id;
    const email_id=context.params.user_email;
    console.log("id: "+user_id+" email: "+email_id);

return admin.firestore().collection("Notifications").doc(user_id).collection("Accepted_Friend_Requests").doc(email_id).get().then((queryResult)=>{

        //main
        const from_user_id=queryResult.data().id;
        const from_name=queryResult.data().name;
        const from_email=queryResult.data().email;
        const from_imagee=queryResult.data().image;
        const noti_id=queryResult.data().notification_id;
        const timestamp=queryResult.data().timestamp;

        const from_data=admin.firestore().collection("Users").doc(from_user_id).get();
        const to_data=admin.firestore().collection("Users").doc(user_id).get();

        return Promise.all([from_data,to_data]).then(result=>{

            const from_image=result[0].data().image;
            const from_email=result[0].data().email;
            const from_token=result[0].data().token_id;

          const payload={
               data:{
                notification_id:noti_id,
                timestamp:timestamp,
                friend_id:from_user_id,
                friend_name:from_name,
                friend_email:from_email,
                friend_image:from_imagee,
                friend_token:from_token,
                title:from_name,
                body:"Accepted your friend request",
                click_action:"com.app.ej.ms.TARGET_ACCEPTED"
              }
            };
            // Send a message to devices subscribed to the provided topic.
             return admin.messaging().sendToDevice(to_token,payload).then(function (results) {
            // See the MessagingTopicResponse reference documentation for the
            // contents of response.
            console.log("Successfully sent message: ", results);
            console.log("Error: ", results.results[0].error);
            return;
            })
            .catch(function (error) {
                console.log("Error sending message: ", error);
            });
          });
    });
});

Ниже приведен код, приведенный на веб-сайте GitHub в качестве примера того, как управлять просроченными токенами в облаке с использованием базы данных Firebase Realtime .

'use strict';

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

/**
 * Triggers when a user gets a new follower and sends a notification.
 *
 * Followers add a flag to `/followers/{followedUid}/{followerUid}`.
 * Users save their device notification tokens to `/users/{followedUid}/notificationTokens/{notificationToken}`.
 */
exports.sendFollowerNotification = functions.database.ref('/followers/{followedUid}/{followerUid}')
    .onWrite((change, context) => {
      const followerUid = context.params.followerUid;
      const followedUid = context.params.followedUid;
      // If un-follow we exit the function.
      if (!change.after.val()) {
        return console.log('User ', followerUid, 'un-followed user', followedUid);
      }
      console.log('We have a new follower UID:', followerUid, 'for user:', followedUid);

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

      // Get the follower profile.
      const getFollowerProfilePromise = admin.auth().getUser(followerUid);

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

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

      return Promise.all([getDeviceTokensPromise, getFollowerProfilePromise]).then(results => {
        tokensSnapshot = results[0];
        const follower = 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 follower profile', follower);

        // Notification details.
        const payload = {
          notification: {
            title: 'You have a new follower!',
            body: `${follower.displayName} is now following you.`,
            icon: follower.photoURL
          }
        };

        // Listing all tokens as an array.
        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);
      });
    });

Ниже мое редактирование моего исходного кода Firestore с использованием функции (как подробно описано в примере GitHub), которая проверяет токены с истекшим сроком действия из массива токенов, а не просто проверяет один токен.

'use-strict'

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


exports.sendAcceptFriendRequest=functions.firestore.document("Notifications/{user_id}/Accepted_Friend_Requests/{user_email}").onWrite((change,context)=> {

    const user_id  = context.params.user_id;
    const email_id = context.params.user_email;
    const db = admin.firestore();

    console.log("id: " + user_id + " email: " + email_id);

return db.collection("Notifications").doc(user_id).collection("Accepted_Friend_Requests").doc(email_id).get().then((queryResult)=>{

        const from_user_id = queryResult.data().id;
        const from_name    = queryResult.data().name;
        const from_email   = queryResult.data().email;
        const from_imagee  = queryResult.data().image;
        const noti_id      = queryResult.data().notification_id;
        const timestamp    = queryResult.data().timestamp;

        const from_data = db.collection("Users").doc(from_user_id).get();
        const to_data   = db.collection("Users").doc(user_id).get();

        const device_tokens = queryResult.data().token_ids;
        let tokensSnapshot; // The snapshot to the user's tokens.
        let tokens;  // The array containing all the user's tokens.

        // https://howtofirebase.com/promises-for-firebase-bbb9d0d595ed
        return Promise.all([from_data, to_data, device_tokens]).then(result=>{

            const from_image=result[0].data().image;
            const from_email=result[0].data().email;

            tokensSnapshot = result[2];
            // Listing all tokens as an array.
            tokens = Object.keys(tokensSnapshot.val());

          const payload={
               data:{
                notification_id:noti_id,
                timestamp:timestamp,
                friend_id:from_user_id,
                friend_name:from_name,
                friend_email:from_email,
                friend_image:from_imagee, // string from token gone
                title:from_name,
                body:"Accepted your friend request",
                click_action:"com.app.ej.ms.TARGET_ACCEPTED"
              }   
            };

            // 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());
                }
            }
            else {
                console.log("Successfully sent friend request: ", tokens[index], response);
            }
            });
            return Promise.all(tokensToRemove);
        });             
          });
});

Поскольку я не смог найти эквивалент Firestore для примера GitHub, я хотел бы попросить вас следовать моей логике, если мой файл Firestore node.js действительно эквивалентен и работает, как и ожидалось.

Мой второй вопрос: "tokensToRemove.push (tokensSnapshot.ref.child (tokens [index]). Remove ());" в примере GitHub. Как это переводится в Firestore? Я думал, что это может сработать, но "ref" - это строго База данных в реальном времени, не так ли?

Мой третий вопрос: можно ли в Promise.all иметь три поля? "Promise.all ([from_data, to_data, device_tokens]). Then (result => {" Я только когда-либо видел, чтобы он использовался с одним или двумя полями.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...