user1889692
user1889692

Reputation:

Update Sub-collections on CloudFunctions

I need help with something.

I have 2 collections on my project, one is called Products and another called Users.

I’m duplicating the selected product information into a sub-collection of users as favorites, in this case:

users(collection) > user(doc) > favorites(collection) > product (doc)

My idea is to create a cloud-function that will watch for any updates on any product in the "product collection" product(collection) > product(doc) and then reflect those changes on the users > favorites sub-collection by updating the values of the products here:

users(collection) > user(doc) > favorites(collection) > product (doc)

How is this possible from index.js ? This my code:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

    exports.updateFavoritedProducts = functions.firestore.document('products/{productId}').onUpdate((change, context) => {

admin.firestore().collection('products').get(queryProductsSnapshot => {

    queryProductsSnapshot.forEach(productQuery => {
    const pricePQ = productQuery.price;

    console.log('tetesfsf');

    return admin.firestore().collection('users').get(queryUsersSnapshot => {
            queryUsersSnapshot.forEach(userSnapshot => {

                return admin.firestore().collection('users').doc(userSnapshot.id).collection('favorites').get(queryUserProductsSnapshot => {
                    queryUserProductsSnapshot.forEach(queryUserProductSnapshot => {
                        if (queryUserProductSnapshot.id === productQuery.id) {

                            return admin.firestore().doc(`users/${userSnapshot.id}/favorites/${queryUserProductSnapshot.id}`).update({ amountVolume: '123456'
                            })
                        } else {
                            console.log("No events found");
                            return null
                        }
                    })
                });
            })
            })
    });
})
});

Upvotes: 2

Views: 3218

Answers (3)

Madhav Kumar
Madhav Kumar

Reputation: 1114

I used user1889692's answer to update all the documents in a even deeply nested sub-collection in my project.

timeline(collection) > timeline(doc) > publisherId(collection) > publisherIdId(doc) > posts(collection) > postId(doc)

enter image description here

This is my working code:

 exports.onCreateTimelineTest = functions.firestore
   .document("/timelineTest/{buguId}")
   .onCreate(async (snapshot, context) => {

 const timeNow =new Date();
 const db = admin.firestore();
     return db.collection("timeline")
     .get()
     .then((timelineQuerySnapshot) => {
     timelineQuerySnapshot.forEach(async(timelineQuerySnapshot) => {


       console.log("all the documnets inside timeline are", timelineQuerySnapshot.id);

        await db.collection("timeline")
        .doc(timelineQuerySnapshot.id)
         .collection("publisherId")
         .get()
         .then((publisherSnapshot)=>{
         publisherSnapshot.forEach(async(publisherSnapshot)=>{


           console.log("all the documnets inside timeline are", publisherSnapshot.id);

         await db.collection("timeline")
          .doc(timelineQuerySnapshot.id)
          .collection("publisherId")
          .doc(publisherSnapshot.id)
          .collection("posts")
          .where('uploadTime', '<=', timeNow)
          .get()
          .then((postSnap)=>{
         postSnap.forEach(async(postSnap)=>{


         console.log("all the documnets inside timeline are", postSnap.id);

         return db.collection("timeline")
         .doc(timelineQuerySnapshot.id)
         .collection("publisherId")
         .doc(publisherSnapshot.id)
         .collection("posts")
         .doc(postSnap.id)
         .set({
         'name': 'madhav'
                          }).catch((err)=>{
                          console.log('Error getting documents', err);
                          return Promise.reject(err);
                          });
                       });
         return null
         }).catch((err) => {
                    console.log('Error getting documents', err);
                    return Promise.reject(err);
                   });
         });
         return null
         }).catch((err) => {
          console.log('Error getting documents', err);
          return Promise.reject(err);
         });
     });
     return null
     }).catch((err) => {
      console.log('Error getting documents', err);
      return Promise.reject(err);
     });

  });

Upvotes: 0

user1889692
user1889692

Reputation:

I finally figured out how to do this with nesting promises. Here is the solution:

exports.updateFavoritedProducts = functions.firestore.document('products/{productId}').onUpdate((change, context) => {
    const data = change.after.data();
    const productID = data.id;

 return db.collection('products').where('id', '==', productID).get().then((productsQuerySnap) => {

    productsQuerySnap.forEach((productQuerySnap) => {
        const newPrice = productQuerySnap.data().price;
        const newPriceUnit = productQuerySnap.data().priceUnit;

        db.collection('users').get().then((usersQuerySnap) => {
            usersQuerySnap.forEach((userQuerySnap) => {

                return db.collection('users').doc(userQuerySnap.id).collection('favorites').doc(productQuerySnap.id).update({ 
                    price: newPrice,
                    priceUnit : newPriceUnit

                 }).catch((err) => {
                    console.log('Error getting documents', err);
                    return Promise.reject(err);
                    });
                });
                return null
            })
            .catch((err) => {
                console.log('Error getting documents', err);
                return Promise.reject(err);
            });
        return null
    });
    return null
})
    .catch((err) => {
        console.log('Error getting documents', err);
        return Promise.reject(err);
    });
});

Upvotes: 1

Frank van Puffelen
Frank van Puffelen

Reputation: 598708

If you want to create a Cloud Function that triggers on all product updates for all users, you declare it as:

functions.firestore.document('users/{userId}/products/{productId}').onUpdate((change, context) => {

If you then want to access userId or productId inside the function body, you can get them as:

context.params.userId
context.params.productId

Upvotes: 4

Related Questions