I have a function that should send notification when someone adds a comment. But this error is shown in log.

TypeError: result[0].data is not a function
    at Promise.all.then.result (/srv/lib/index.js:19:35)
    at <anonymous>
    at process._tickDomainCallback (internal/process/next_tick.js:229:7)

And this is my function. What is wrong in here? How to change this?

/*eslint-disable */

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

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

exports.apptTrigger = functions.firestore.document("Comments/{anydocument}").onCreate((snap, context) =>  {

    const receiver = snap.data().idUserImage;

    const messageis = snap.data().comment;


    const toUser = admin.firestore().collection("token").where('idUser', '==', receiver).get();


    return Promise.all([toUser]).then(result => {

      const tokenId = result[0].data().token;

    const notificationContent = {
           notification: {
              title: "Dodano komentarz",
              body: messageis,
              icon: "default",
              sound : "default"
            }};
               return admin.messaging().sendToDevice(
                    tokenId,
                    notificationContent
                ).then(results => {
            console.log("Notification sent!");
            //admin.firestore().collection("notifications").doc(userEmail).collection("userNotifications").doc(notificationId).delete();
          });
        });
});

2 Answers

2
Renaud Tarnec On Best Solutions

This is normal since the promise returned by the get() method of a Query returns a QuerySnapshot which "contains zero or more DocumentSnapshot objects representing the results of a query". Therefore there is no data() method for result[0].

The QuerySnapshot documentation (link above) says:

The documents can be accessed as an array via the docs property or enumerated using the forEach method. The number of documents can be determined via the empty and size properties.

Therefore you should use the docs property, which returns "an array of all the documents in the QuerySnapshot" and do as follows:

const tokenId = result[0].docs[0].data().token;

Note however that you don't need to use Promise.all in your case, since you are passing to it an array with only one element. You just have to use the QuerySnapshot returned by get() and use its docs property as follows:

exports.apptTrigger = functions.firestore
  .document('Comments/{anydocument}')
  .onCreate((snap, context) => {
    const receiver = snap.data().idUserImage;
    const messageis = snap.data().comment;

    const toUser = admin
      .firestore()
      .collection('token')
      .where('idUser', '==', receiver)
      .get();

    return toUser
      .then(querySnapshot => {
        const tokenId = querySnapshot.docs[0].data().token;

        const notificationContent = {
          notification: {
            title: 'Dodano komentarz',
            body: messageis,
            icon: 'default',
            sound: 'default'
          }
        };

        return admin.messaging().sendToDevice(tokenId, notificationContent);
      })
      .then(results => {   //If you don't need the following console.log() just remove this then() 
        console.log('Notification sent!');
        return null;
      });
  });
1
Sreehari On

The error states that "result[0].data" is not function. However, you are accessing the "data" as function from your result[0] object.

 const tokenId = result[0].data().token;

You may have to change the above line of code to

const tokenId = result[0].data.token;

But before that I suggest to check if "data" itself is defined.

const tokenId;
if(result[0].data)
  tokenId = result[0].data.token;