Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firestore get all document of a sub collection

I want to create a function where it generate report every 2 hours. For now the schedule I fixed it for testing purposes. I am currently facing the problem of getting all of the data of transactions from shops in order to calculate and generate a record in reports collection. The below code return error message of TypeError: Cannot read property 'map' of undefined.

exports.generateReport = functions.pubsub.schedule('25 14 * * *').onRun(async (context) => {
    const shopSnapshot = await db.collection("shops").get();
    const shopDoc = shopSnapshot.docs.map(doc => doc.data());

    console.log(shopDoc);

    for(var i=0; i<shopDoc.length; i++){
        console.log(shopDoc[i].id);
        if(shopDoc[i].id !== "" || shopDoc[i].id !== null){
            console.log("Enter if:"+shopDoc[i].id);
            let transactionSnapshot = db.collection("shops").doc(shopDoc[i].id).collection("transactions").get();
            let transactionDoc = transactionSnapshot.docs.map(document => document.data());
            console.log(transactionDoc);
        }
    }

The image of firestore


1 Answers

You should use Promise.all() to wait that all the asynchronous get() operations are completed before you proceed.

You could do as follows:

exports.generateReport = functions.pubsub.schedule('25 14 * * *').onRun(async (context) => {
    const shopSnapshot = await db.collection("shops").get();
    const shopDoc = shopSnapshot.docs.map(doc => doc.data());

    console.log(shopDoc);

    const promises = [];
 
    for(var i=0; i<shopDoc.length; i++){
        console.log(shopDoc[i].id);

        if(shopDoc[i].id !== "" || shopDoc[i].id !== null){
            promises.push(db.collection("shops").doc(shopDoc[i].id).collection("transactions").get());
        }
    }

    const snapshotArrays = await Promise.all(promises);
    // snapshotArrays contains an array of arrays of QueryDocumentSnapshots 

    snapshotArrays.forEach(snapArray => {
        snapArray.forEach(snap => {
             // Proceed here with the snap (DocumentSnapshot)
             //E.g. sum up the amount or points values
           }))
        })
    }); 
    //Or call map on snapshotArrays.docs 
  
    // ....
    return null;  // or return the promise returned by an asynchronous method

Note that you may need to do this calculation in a Transaction, within your Cloud Function, to avoid a new transaction document is added while you are calculating.

The Admin SDK for Node.js includes the getAll() method, which "retrieves multiple documents from Firestore and holds a pessimistic lock on all returned documents."

like image 102
Renaud Tarnec Avatar answered Dec 23 '25 19:12

Renaud Tarnec



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!