0

I am struggling with a cloud function that updates the "presence" property on a collectionGroup "place_users".

My query does not filter the entries by "presence" == true. It used to work client-side, but I switched it to cloud-function and it no longer filters. All documents are returned.

exports.updatePoiPresence = functions.https.onCall((data: any, context: any) => {

    return new Promise((resolve, reject) => {

        return store.collectionGroup("place_users",
                (ref: any) => ref
                .where("user_id", "==", context.auth.uid)
                .where("day_stamp", "<", data.start_of_day / 1000)
                .where("presence", "==", true))
            .get()
            .then(
                (q_snapshot: any) => {

                    return q_snapshot.forEach((snapshot: any) => {
                        functions.logger.log("no docs value data fct:", snapshot.data())


                        snapshot.ref.update({
                                presence: false
                            })
                            .then((a: any) => {
                                resolve("ok");
                            })
                            .catch((error: any) => {
                                functions.logger.log("error survenue", error);
                                reject("Rejet pas identifie")
                            })
                    });


                })
    });
});

Cloud function console

I have a series of indexes created for that collectionGroup: (I have no idea which one are used in what situation since I have ve been clicking on the index creator wizard through the console without thinking about their purpose.

List of index

Renaud Tarnec
  • 79,263
  • 10
  • 95
  • 121
Raphael St
  • 661
  • 8
  • 23
  • Where do you log the "no docs value data fct" string that we can see in your screenshot? – Renaud Tarnec Jul 26 '20 at 15:30
  • Hi @RenaudTarnec, I just edited my post – Raphael St Jul 26 '20 at 15:32
  • It looks like you tried to port code from Angular into backend code running Cloud Functions. That's not going to work, as the SDKs have different syntax. Also, no need to create a new promise here. All the APIs already deal with promises - just use the ones you're given by the API. – Doug Stevenson Jul 26 '20 at 16:46

1 Answers1

1

It seems that you are uncorrectly querying the database with:

    return store.collectionGroup("place_users",
        (ref: any) => ref
            .where("user_id", "==", context.auth.uid)
            .where("day_stamp", "<", data.start_of_day / 1000)
            .where("presence", "==", true))
        .get()

The collectionGroup() method takes only one argument. You should do as follow:

    return store.collectionGroup("place_users")
            .where("user_id", "==", context.auth.uid)
            .where("day_stamp", "<", data.start_of_day / 1000)
            .where("presence", "==", true))
        .get()

In addition, note that the Firebase asynchronous methods return promises. You don't need to wrap your code in return new Promise();.

The following should do the trick.

const store = admin.firestore();

exports.updatePoiPresence = functions.https.onCall((data: any, context: any) => {

    return store.collectionGroup("place_users")
        .where("user_id", "==", context.auth.uid)
        .where("day_stamp", "<", data.start_of_day / 1000)
        .where("presence", "==", true)
        .get()
        .then((q_snapshot: any) => {
            const promises = [];
            q_snapshot.forEach((snapshot: any) => {
                functions.logger.log("no docs value data fct:", snapshot.data())
                promises.push(snapshot.ref.update({ presence: false }));
            });
            return Promise.all(promises);
        })
        .catch((error: any) => {
            functions.logger.log("error survenue", error);
            return null;
        })

});

Note that we use Promise.all(), since we execute several asynchronous operations to the database in parallel (using the update() method, which returns a promise, see the doc).


You may also have a look at the official "Cloud Functions for Firebase: getting started with TypeScript" article. In particular, note how the Cloud Functions are exported, compare to JavaScript (exports. -> export const).

Renaud Tarnec
  • 79,263
  • 10
  • 95
  • 121
  • 1
    Thanks it is all good, except for the double return statement, the first return q_snapshot should be removed, only the return Promise.all should exist. I cant help but wonder where the collectionGroup method with the callback function as second argument comes from, cause I actually saw it at different locations : For example this guy was using the same syntax :https://stackoverflow.com/questions/56313259/firestore-query-collectiongroup-by-document-id?noredirect=1&lq=1 – Raphael St Aug 03 '20 at 17:01