最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Storing FCM tokens online - Stack Overflow

programmeradmin1浏览0评论

I am working with an iOS app which calls an Firebase cloud function, to store FCM tokens, for later use when sending notifications. The problem is that it does not work.

I am using a Cloud Firestore database.

When the function is called, here is what I want to happen. The function checks the parameters against a database. If the data in the provided parameter is already found in the DB then nothing should happen. If it is not found, then it should be added to the DB.

My cloud function code is below. I would be glad if someone could help me find the precise issue.

exports.addNewElement = functions.https.onCall((data, context) => {
  console.log('--addNewElement-- has been called with:\n' + data.fcmToken + '\n!!');
  var collectionRef = db.collection("THE_COLLECTION");

  // Create a query against the collection.
  var query = collectionRef.where("fcmToken", "==", data.fcmToken);
  query.get().then(function(doc) {
    if (doc.exists) { // We should do nothing.
        console.log("Document data:", doc.data());
    } else { // We should add the new element.
        // doc.data() will be undefined in this case
        console.log("No such document!");
        collectionRef.add({"fcmToken": fcmToken})
    }
  }).catch(function(error) {
    console.log("Error getting document:", error);
  });
});

I could imagine other directions to handle FCM tokens. Is there any remend way to use as best practice?

I am working with an iOS app which calls an Firebase cloud function, to store FCM tokens, for later use when sending notifications. The problem is that it does not work.

I am using a Cloud Firestore database.

When the function is called, here is what I want to happen. The function checks the parameters against a database. If the data in the provided parameter is already found in the DB then nothing should happen. If it is not found, then it should be added to the DB.

My cloud function code is below. I would be glad if someone could help me find the precise issue.

exports.addNewElement = functions.https.onCall((data, context) => {
  console.log('--addNewElement-- has been called with:\n' + data.fcmToken + '\n!!');
  var collectionRef = db.collection("THE_COLLECTION");

  // Create a query against the collection.
  var query = collectionRef.where("fcmToken", "==", data.fcmToken);
  query.get().then(function(doc) {
    if (doc.exists) { // We should do nothing.
        console.log("Document data:", doc.data());
    } else { // We should add the new element.
        // doc.data() will be undefined in this case
        console.log("No such document!");
        collectionRef.add({"fcmToken": fcmToken})
    }
  }).catch(function(error) {
    console.log("Error getting document:", error);
  });
});

I could imagine other directions to handle FCM tokens. Is there any remend way to use as best practice?

Share Improve this question edited Dec 14, 2018 at 10:42 droidBomb 8805 silver badges8 bronze badges asked Dec 3, 2018 at 6:45 MichelMichel 11.8k21 gold badges102 silver badges219 bronze badges 4
  • What's the problem? – Frank van Puffelen Commented Dec 3, 2018 at 7:01
  • The problem is that I am not storing anything now. Because what I do is not working. Beside, I am not sure the way I want to do it is the best practice. I could store the token by making DB write request directly from the app, I have already tried successfully, but I would like to avoid storing twice the same token, that is why I thought using a cloud function might be a better approach. – Michel Commented Dec 3, 2018 at 7:14
  • why you used collectionRef.add({"fcmToken": fcmToken}) insted of collectionRef.add({"fcmToken": data.fcmToken}) – Jatin Kathrotiya Commented Dec 3, 2018 at 7:20
  • Right! This was a mistyping. Sorry! – Michel Commented Dec 3, 2018 at 8:28
Add a ment  | 

1 Answer 1

Reset to default 5

I take a bit of a different approach. I have an ionic app and after the app has registered with FCM (we have FCM token), I add the token to a 'devices' collection straight from the app. This way, a user can log in to more then one device and we will have the token for each device enabling us to send the message to each device. If you want to send a message to a user, you query the devices collection for that uid to get all the tokens for that user

Saving the token:

    private saveTokenToFirestore(person: Person, token) {
        if (!token) return;
        const devicesRef = this.afs.collection('devices')

        const docData = { 
          token,
          userId: person.id,
        }

        return devicesRef.doc(token).set(docData)
      }

where person.id is the firebase uid.

I then use firebase functions to monitor some nodes to figure out when to send FCM messages.

e.g. we have teams with persons as members and they can chat to each other. When a person sends a message to a team, each team member (except the sender himself) needs to get a notification.

Sending a notification to all members except the sender himself:

exports.chatMessageOnCreateSendFcm = functions.firestore
    .document('chatGroups/{teamId}/messages/{messageId}')
    .onCreate(async (snap, context) => {
        const data = snap.data();
        const teamId = context.params.teamId;
        const name = data.pName;
        const message = data.msg;
        const userId = data.pId;

        // Notification content
        const payload = {
            notification: {
                title: name,
                body: message,
            }
        }

        const db = admin.firestore();

        // get the team (chatGroup)
        const teamRef = db.collection('teams').doc(teamId);
        const teamSnapshot = await teamRef.get();
        const team = teamSnapshot.data();
        const devicesRef = db.collection('devices');
        const queries: Promise<FirebaseFirestore.QuerySnapshot>[] = team.members
            .filter(f => f.id !== userId)
            .map(member => {
                return devicesRef.where('userId', '==', member.id).get();
            });

        return Promise.all(queries)
            .then((querySnapshots) => {
                const tokens = [];
                querySnapshots.forEach(snapShot => {
                    if (snapShot) {
                        snapShot.docs.forEach(doc => {
                            if (doc) {
                                const token = doc.data().token;
                                if (token) {
                                    tokens.push(token);
                                }
                            }
                        })
                    }
                });

                if (tokens.length === 0) {
                    return Promise.resolve(null);
                } else {
                    return admin.messaging().sendToDevice(tokens, payload);
                }
            })
            .catch(err => {
                console.error(err);
                return Promise.resolve(null);
            });
    });

You can modify the above to suit your needs. Hope it helps

发布评论

评论列表(0)

  1. 暂无评论