1
votes

So, I don't really know how to write JS, I am developing a mobile app in Flutter, and I would be grateful for some help and clarifications regarding Future/Promises in JS.

I got a collection of posts for each user, and I want to create an .onCreate function which when a user posts a new post (a new document is created inside the 'posts/userId/user_posts' collection), then it gets all the user's followers (from a collection 'user_followers/userUid') and for each follower, it writes the postUid and postOwnerUid to that follower's newsFeed collection ('user_news_feed/followerId').

This is what I got right now, but I am walking blind, since I really don't know JS and I don't know how can I await a write function while inside a get function.

And how do I prevent Cloud Timeouts? If for instance the user has 1000 followers, how can I prevent Firebase from shutting down my function and making sure all the followers are notified?

exports.writeToUserNewsFeed = functions.firestore
.document('posts/{userId}/user_posts/{postId}')
.onCreate((snap, context) => {
    const postData = snap.data();
    const postUid = postData['post_uid'];
    const userUid = postData['user_uid'];
    const postCreationDate = postData['post_creation_date'];

    var docRef = db.collection('user_followers').doc(userUid).collection('followers');

    docRef.get().then((querySnapshot) => {
        querySnapshot.forEach((doc) => {
            db.collection('user_news_feed')
            .doc(doc.data['uid'])
            .collection('feed')
            .document(postUid)
            .set({
                'post_uid': postUid,
                'user_uid': userUid,
                'post_uid': postCreationDate,
            });
        });
    });
});
1

1 Answers

1
votes

As explained in the doc, in a background Cloud Function like an onCreate() for Firestore, you need to return a Promise when all the asynchronous work is completed. So in your case, one possibility is to use Promise.all() because you don't know upfront how many documents are in the followers subcollection. Since Promise.all() returns a single Promise you can include it in the Promise chain that you need to return in the Cloud Function.

exports.writeToUserNewsFeed = functions.firestore
    .document('posts/{userId}/user_posts/{postId}')
    .onCreate((snap, context) => {
        const postData = snap.data();
        const postUid = postData['post_uid'];
        const userUid = postData['user_uid'];
        const postCreationDate = postData['post_creation_date'];

        var followersColRef = db.collection('user_followers').doc(userUid).collection('followers');

        return followersColRef.get().then((querySnapshot) => {   // <= See return here

            const promises = [];

            querySnapshot.forEach((doc) => {
                promises.push(
                    db.collection('user_news_feed')
                        .doc(doc.data['uid'])
                        .collection('feed')
                        .doc(postUid)
                        .set({
                            'post_uid': postUid,
                            'user_uid': userUid,
                            'post_uid': postCreationDate,
                        })
                );
            });

            return Promise.all(promises);   // <= See return here

        })
            .catch(error => {
                console.log(error);
                return null;
        })

    });

Note that instead of using Promise.all() you could also use a batched write but there is a limit of 500 operations for a batched write.