如何在Firebase node.js云功能中推送通知?

时间:2019-12-07 17:18:32

标签: node.js firebase push-notification google-cloud-firestore google-cloud-functions

我想用node.js创建一个函数,但是我陷入了困境。

我要做什么的解释:

首先,当将新文档添加到路径配置文件/ {profileID} / posts / {newDocument}

时,该函数将触发

该功能将向以下所有用户发送通知。问题来了。

我的个人资料集合中还有另一个集合,该集合是关注者,其中包含字段followerID的文档。

我想使用此followerID并将其用作文档ID,以在我已添加到个人资料文档的情况下访问tokenID字段。

像这样:

..(profile / followerID).get();然后访问tokenID字段的字段值。

我当前的代码:-Index.js

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

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


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


exports.fcmTester = functions.firestore.document('profile/{profileID}/posts/{postID}').onCreate((snapshot, context) => {
    const notificationMessageData = snapshot.data();

    var x = firestore.doc('profile/{profileID}/followers/');

    var follower;

    x.get().then(snapshot => {
      follower = snapshot.followerID;
    });



    return admin.firestore().collection('profile').get()
        .then(snapshot => {
            var tokens = [];

            if (snapshot.empty) {
                console.log('No Devices');
                throw new Error('No Devices');
            } else {
                for (var token of snapshot.docs) {
                    tokens.push(token.data().tokenID);
                }

                var payload = {
                    "notification": {
                        "title": notificationMessageData.title,
                        "body": notificationMessageData.title,
                        "sound": "default"
                    },
                    "data": {
                        "sendername": notificationMessageData.title,
                        "message": notificationMessageData.title
                    }
                }

                return admin.messaging().sendToDevice(tokens, payload)
            }

        })
        .catch((err) => {
            console.log(err);
            return null;
        })

});

我的firestore数据库说明。

个人资料| profileDocument |帖子和关注者|追随者收集文件和张贴收集文件

我有一个名为profile的父集合,它包含文档,因为这些文档的任何集合都包含一个我要访问的字段tokenID,但是我不会仅对关注者的所有用户(追随该profile的用户)执行此操作),因此我创建了一个名为followers的新集合,其中包含所有Followers ID,我想获取每个followerID,并针对每个ID将tokenID推送到令牌列表中。

1 个答案:

答案 0 :(得分:3)

如果我正确理解您的问题,则应该执行以下操作。请参阅下面的说明。

exports.fcmTester = functions.firestore.document('profile/{profileID}/posts/{postID}').onCreate((snapshot, context) => {

    const notificationMessageData = snapshot.data();
    const profileID = context.params.profileID;

    // var x = firestore.doc('profile/{profileID}/followers/');  //This does not point to a document since your path is composed of 3 elements

    var followersCollecRef = admin.firestore().collection('profile/' + profileID + '/followers/');  
    //You could also use Template literals `profile/${profileID}/followers/`

    return followersCollecRef.get()
    .then(querySnapshot => {
        var tokens = [];
        querySnapshot.forEach(doc => {
            // doc.data() is never undefined for query doc snapshots
            tokens.push(doc.data().tokenID);
        });

        var payload = {
            "notification": {
                "title": notificationMessageData.title,
                "body": notificationMessageData.title,
                "sound": "default"
            },
            "data": {
                "sendername": notificationMessageData.title,
                "message": notificationMessageData.title
            }
        }

        return admin.messaging().sendToDevice(tokens, payload)

    }); 

首先,您要做var x = firestore.doc('profile/{profileID}/followers/');时不会声明DocumentReference,因为您的路径由3个元素(即Collection / Doc / Collection)组成。另请注意,在Cloud Function中,您需要使用Admin SDK才能读取其他Firestore文档/集合:因此,您需要执行admin.firestore()var x = firestore.doc(...)不起作用)。

第二,您不能仅通过执行profileID来获得{profileID}的值:您需要使用context对象,如下所示const profileID = context.params.profileID;

因此,应用上述内容,我们声明一个CollectionReference followersCollecRef并调用get()方法。然后,我们使用querySnapshot.forEach()遍历此Collection的所有文档,以填充tokens数组。

其余部分很简单,符合您的代码。


最后,请注意,从v1.0版本开始,您应该使用admin.initializeApp();简单地初始化Cloud Functions,请参阅https://firebase.google.com/docs/functions/beta-v1-diff#new_initialization_syntax_for_firebase-admin


根据您的评论进行更新

以下Cloud Function代码将查找每个关注者的个人资料文档,并使用该文档中tokenID字段的值。

(请注意,您也可以将tokenID直接存储在Follower文档中。您将复制数据,但这在NoSQL世界中很常见。)

exports.fcmTester = functions.firestore.document('profile/{profileID}/posts/{postID}').onCreate((snapshot, context) => {

    const notificationMessageData = snapshot.data();
    const profileID = context.params.profileID;

    // var x = firestore.doc('profile/{profileID}/followers/');  //This does not point to a document but to a collectrion since your path is composed of 3 elements

    const followersCollecRef = admin.firestore().collection('profile/' + profileID + '/followers/');
    //You could also use Template literals `profile/${profileID}/followers/`

    return followersCollecRef.get()
        .then(querySnapshot => {
            //For each Follower document we need to query it's corresponding Profile document. We will use Promise.all()

            const promises = [];
            querySnapshot.forEach(doc => {
                const followerDocID = doc.id;
                promises.push(admin.firestore().doc(`profile/${followerDocID}`).get());  //We use the id property of the DocumentSnapshot to build a DocumentReference and we call get() on it.
            });

            return Promise.all(promises);
        })
        .then(results => {
            //results is an array of DocumentSnapshots
            //We will iterate over this array to get the values of tokenID

            const tokens = [];
            results.forEach(doc => {
                    if (doc.exists) {
                        tokens.push(doc.data().tokenID);
                    } else {
                        //It's up to you to decide what you want to to do in case a Follower doc doesn't have a corresponding Profile doc
                        //Ignore it or throw an error
                    }
            });

            const payload = {
                "notification": {
                    "title": notificationMessageData.title,
                    "body": notificationMessageData.title,
                    "sound": "default"
                },
                "data": {
                    "sendername": notificationMessageData.title,
                    "message": notificationMessageData.title
                }
            }

            return admin.messaging().sendToDevice(tokens, payload)

        })
        .catch((err) => {
            console.log(err);
            return null;
        });

});