D.Hodges
D.Hodges

Reputation: 2107

firebase cloud messaging not sending push notification - Value for argument "value" is not a valid query constraint

I pushed the following FCM push notification to firebase functions:

import * as functions from 'firebase-functions';

import * as admin from 'firebase-admin';

admin.initializeApp();

exports.newSubscriberNotification = functions.firestore
    .document('messages/{id}')
    .onUpdate(async event => {
        const data = event.after.data();
        const content = data ? data.content : '';
        const toUserId = data ? data.toUserId : '';

        const payload = {
            notification: {
                title: 'New message',
                body: `${content}`
            }
        };

        const db = admin.firestore();
        const devicesRef = db.collection('devices').where('userId', '==', toUserId);

        const devices = await devicesRef.get();
        const tokens: any = [];

        devices.forEach(result => {
            const token = result.data().token;
            tokens.push(token);
          });

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

In the code I'm using .onUpdate, which I assume should trigger when one of the messages collection is updated. This is a messaging app so when ever the messaging collection is updated I'd like to trigger a push notification to the receiving user.

I get the tuUserId and use it to get the device token of that user from the devices collection. I'm testing now so the toUserId is identical to the from userId because it's just using my device...so hopefully when I update the message.doc() it sends a push notification.

Here is the message collection in firebase:

enter image description here

This is the function error log:

11:04:22.937 PM
newSubscriberNotification
Function execution started
11:04:22.946 PM
newSubscriberNotification
Error: Value for argument "value" is not a valid query constraint. Cannot use "undefined" as a Firestore value.
    at Object.validateUserInput (/srv/node_modules/@google-cloud/firestore/build/src/serializer.js:273:15)
    at validateQueryValue (/srv/node_modules/@google-cloud/firestore/build/src/reference.js:1844:18)
    at CollectionReference.where (/srv/node_modules/@google-cloud/firestore/build/src/reference.js:956:9)
    at exports.newSubscriberNotification.functions.firestore.document.onUpdate (/srv/lib/index.js:19:49)
    at cloudFunction (/srv/node_modules/firebase-functions/lib/cloud-functions.js:131:23)
    at /worker/worker.js:825:24
    at <anonymous>
    at process._tickDomainCallback (internal/process/next_tick.js:229:7)
11:04:22.957 PM
newSubscriberNotification
Function execution took 21 ms, finished with status: 'error'

I'm pretty sure it doesn't like my .where clause because of this error: at CollectionReference.where (/srv/node_modules/@google-cloud/firestore/build/src/reference.js:956:9)

I'm just not sure why

Upvotes: 0

Views: 755

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 599956

The document in your screenshot contains an array of objects, which your code doesn't handle. You're trying to read toUserId from the root of the document, where it doesn't exist. This means your toUserId has a value of undefined, which Firestore complains about.

It's a bit unusual to see multiple objects/messages in a single document, so you will have to determine if that is really the best approach. But if it is, you will have to determine which of these objects you want to send the notification to. If you want to send to all of these objects, you can loop over them:

exports.newSubscriberNotification = functions.firestore
.document('messages/{id}')
.onUpdate(async event => {
  const allMessages = event.after.data();
  const db = admin.firestore();

  Object.keys(allMessages).forEach((index) => {
    let data = allMessages[index];

    const content = data ? data.content : '';
    const toUserId = data ? data.toUserId : '';

    const payload = {
        notification: {
            title: 'New message',
            body: `${content}`
        }
    };

    const devicesRef = db.collection('devices').where('userId', '==', toUserId);

    const devices = await devicesRef.get();

    ...
  })
});

Upvotes: 1

Related Questions