firebaseloopsgoogle-cloud-firestoregoogle-cloud-functions

Iterate through all users - firestore


I have the following (simplified) setup in firestore

    Collection     Document      FIELD     
    [USERID]   -   [STATUS]   -   date_of_birth: timestamp
                                  last _update: timestamp

    [USERID]   -   [STATUS]   -   date_of_birth: timestamp
                                  last _update: timestamp

    [USERID]   -   [STATUS]   -   date_of_birth: timestamp
                                  last _update: timestamp

    [USERID]   -   [STATUS]   -   date_of_birth: timestamp
                                  last _update: timestamp
...

I want to build a firebase function where, based on the date of birth, the last_update is not allowed to be older than one year (365 days). If last_update > 365 I want to send the user an notification email.

My problem is, how can I iterate through all the [UDERID]'s? What is the best way to do this? Is there a way to get all USERID's (more than 4000) in an array and iterate through them or is there another way?

I saw that there should be a way https://firebase.google.com/docs/auth/admin/manage-users#node.js but I have no idea how to implement this within google cloud functions.

Does someone has an idea/solution???

Thanks a lot!


Solution

  • Okay, I realized that the design of my database isn't very optimal. If anyone is interested in the solution, please find it below.

    This is the index.js for functions:

    const functions = require("firebase-functions");
    const admin = require('firebase-admin')
    const serviceAccount = require('./cerdentials.json')
    admin.initializeApp({
        credential: admin.credential.cert(serviceAccount),
        databaseURL: "https://test-data-eda4b.firebaseio.com"
    });
    
    const nodemailer = require("nodemailer");
    
    let transporter = nodemailer.createTransport({
        service: 'gmail',
        // true for 465, false for other ports
        auth: {
            user: 'your email', // generated ethereal user
            pass: 'passowrd', // generated ethereal password
        },
    });
    
    const auth = admin.auth();
    const db = admin.firestore();
    
    exports.sendEmailToUsers = functions.pubsub.schedule('every 120 minutes').onRun(async (context) => {
        await fatchUsers("").then(res => {
            console.log(res);
        }).catch(e => { console.log(e) })
    })
    
    async function fatchUsers (token) {
        if (token != "") {
            return await auth.listUsers(4, token).then(async (usersList) => {
                usersList.users.forEach(user => {
                    db.collection(user.uid).doc('status').get().then(async snapshot => {
                        if (snapshot.exists) {
                            if (snapshot.data().notifications_softskills_activated) {
                                console.log("send email to this user : " + user.email);
                                var Email_Res = await sendMail(user.email)
                                functions.logger.info(Email_Res)
                            }
                        }
                    })
                })
                if (usersList.pageToken != undefined) {
                    await fatchUsers(usersList.pageToken)
                } else {
                    return true;
                }
            })
        } else {
            return await auth.listUsers(4).then(async (usersList) => {
                usersList.users.forEach(user => {
                    db.collection(user.uid).doc('status').get().then(async snapshot => {
                        if (snapshot.exists) {
                            if (snapshot.data().notifications_softskills_activated) {
                                console.log("send email to this user : " + user.email);
                                var Email_Res = await sendMail(user.email)
                                functions.logger.info(Email_Res)
                            }
                        }
                    })
                })
                if (usersList.pageToken != undefined) {
                    await fatchUsers(usersList.pageToken)
                } else {
                    return true;
                }
            })
        }
    }
    
    async function sendMail (email) {
        return await new Promise(async (resolve, reject) => {
            const mailOptions = {
                from: "testuser@gmail.com", // sender address
                to: email, // list of receivers
                subject: 'test mail', // Subject line
                html: '<h1>this is a test mail.</h1>'// plain text body
            };
            transporter.sendMail(mailOptions, function (err, info) {
                if (err) {
                    reject(err);
                }
                else {
                    resolve(info);
                }
            })
        })
    }