0

In my cloud function i have an array that contains all userId's that need to get a cloud-message(notification)

const aNotify = [{id: 'id001', text: 'specialTextFor001'}, {id: 'id002', text: 'specialTextFor002'};

This is how the devices collection looks like. the Document ID is the token ID but to find them i need to query on the userId

devices

Is it possible to do it through the DB like with a where clause or do I need to do this by getting all devices and in cloud method do a foreach... ?

Renaud Tarnec
  • 79,263
  • 10
  • 95
  • 121
MichaelAngelo
  • 375
  • 2
  • 19
  • CollectionReference's [get()](https://firebase.google.com/docs/reference/js/firebase.firestore.CollectionReference#get) function return a promise that will be resolved with the results of the query. Collect all the promises into a List, and pass that to all() function to respond when the entire set is complete, as explained [here](https://stackoverflow.com/questions/48038490/firestore-with-promises-and-push), right? – Alex Mamo Oct 31 '18 at 12:33
  • @AlexMamo you mean create a promise list of each 'where' clause on the userId ? wouldnt that be overkill ? – MichaelAngelo Oct 31 '18 at 13:30
  • Yes. It won't. Please see Doug's answer from this [post](https://stackoverflow.com/questions/47972620/nested-firestore-asynchronous-listeners-in-android). Is for Android but you can achieve the same thing for web. – Alex Mamo Oct 31 '18 at 13:39

1 Answers1

0

In order to find a device document corresponding to a userId, you have to use a simple query like:

const db = admin.firestore();
db.collection('devices').where("userId", "==", element.id).get();

see the corresponding doc here.

Since you need to make a query for each element of the aNotify array, you need to use Promise.all(), since get() returns a Promise.

Something like the following will work. You have to adapt it in order to correctly return the promises in your Cloud Function (since you didn't share your Cloud Function code it is difficult to give more guidance on this point).

    const db = admin.firestore();

    var aNotify = [{ id: 'id001', text: 'specialTextFor001' }, { id: 'id002', text: 'specialTextFor002' }];

    var promises = []
    aNotify.forEach(function (element) {
        promises.push(db.collection('devices').where("userId", "==", element.id).get());
    });
    return Promise.all(promises)   
        .then(results => {
            results.forEach(querySnapshot => {
                querySnapshot.forEach(function (doc) {
                    console.log(doc.id, " => ", doc.data());
                    //here, either send a notification for each user of populate an array, or....
                    //e.g. return admin.messaging().sendToDevice(doc.data().token, ....);
                });
            });
        });

Note that the results array has exactly the same order than the promises array. So it is not complicated to get the text property of the corresponding object of the aNotify array when you send the notifications.

Shog9
  • 156,901
  • 35
  • 231
  • 235
Renaud Tarnec
  • 79,263
  • 10
  • 95
  • 121
  • Thanks for the help but this will use allot of networking calls right ? I am refering to this part promises.push(db.collection('devices').where("userId", "==", element.id).get()); – MichaelAngelo Oct 31 '18 at 21:32
  • @MichaelAngelo It will query one document by userId (with the assumption that a userId is associated to one device only). With your data model there is no other way... or you denormalize your data and put anything in one document, e.g. in an array. But then you’ll have to take care of the Firestore limits, see https://firebase.google.com/docs/firestore/quotas#limits – Renaud Tarnec Nov 01 '18 at 07:24