1

I want to access a subcollection called 'followers' from a given id under the 'mobile_user', this contains the id's of the followers. I want to loop through each of the id's in the followers subcollection and query data from the 'mobile_user' collection . Notice that the id in the 'followers' subollection is the id of another user under 'mobile_user' which contains the document data i want.

I've tried messing around with promises with no luck, i'm able to do the foreach loop and just query the name as a test but the array gets populated correctly but the populated array with the names of the N users are never returned.

I need some assistance with my code, promises are driving me nuts I can't get the hang around them.

const getFollowers = (data, context) => {
        return new Promise((resolve, reject) => {

            let id = data.id
            const mobileUserRef = db.collection('mobile_user')

            return mobileUserRef.doc(id).collection('followers')
                .get()
                .then(function (doc) {
                    var result = []
                    doc.forEach(function (follower) {
                        mobileUserRef.doc(follower.id).get()
                            .then(function (followerdoc) {
                                result.push({
                                    name: followerdoc.data().name,
                                })
                                console.log(result)
                            })
                    })
                    return Promise.all(result);
                })
        });
    }

The expected result is an array with the data of every id under the followers sub, like this:

In this example only 2 user id's are present

[ { name: 'Luis' }, { name: 'Marb Rocha' } ]
2
  • do the return in the same position as console.log Commented Apr 22, 2019 at 17:54
  • @NabeelKhan i'm still getting a socket hang up Commented Apr 22, 2019 at 18:11

2 Answers 2

1

nothing gets pushed to result by the time the return Promise.all(result); is called, therefore the promise resolves early with no data. you could utilize chaining to return the results once all the promises resolve, as shown below:

const getFollowers = (data, context) => {
    const results = [];

    const id = data.id
    const mobileUserRef = db.collection('mobile_user');

    //return the initial promise, and use chaining to *eventually* return the results
    return mobileUserRef.doc(id).collection('followers')
    .get()
    .then(doc=>{
        //use map to transform the doc results into an array of promises that call each user ref and load the doc
        const promises = doc.map(follower=>{
            return mobileUserRef.doc(follower.id).get()
            .then(followerdoc=>{
                //push items into the results
                results.push({
                    name: followerdoc.data().name,
                })
                return followerdoc;
            })
        })
        //execute all the promises, then return the results
        return Promise.all(promises).then(()=>{
            return results;//return the results, resolving our chain finally
        });
    })

}
Sign up to request clarification or add additional context in comments.

4 Comments

thank you, this is helpful. Although when i try to run it i'm getting the error Unhandled error TypeError: doc.map is not a function
@Louis that would seem to indicate that doc is not an Array, or the environment the code is running in doesn't have the Array.prototype.map method, which was added in es5 i believe, so it may not be available in all environments. To suggest a fix, i would need to know more about the environment.
thank you, the array was under doc.docs.map and I'm now getting the result i wanted. I love you
@Louis no problem, glad you got it figured out
1

You need to add some promises to the array you pass to Promise.all(), so I think you should do as follows:

  const getFollowers = (data, context) => {
    let id = data.id;
    const mobileUserRef = db.collection('mobile_user');

    return mobileUserRef
      .doc(id)
      .collection('followers')
      .get()
      .then(querySnapshot => {
        var result = [];
        querySnapshot.forEach(follower => {
          result.push(mobileUserRef.doc(follower.id).get());
        });
        return Promise.all(result);
      })
      .then(results => {
        var finalResult = [];
        results.forEach(followerdoc => {
          finalResult.push({
            name: followerdoc.data().name
          });
        });
        return finalResult;
      });
  };

PS: not sure why you have a context parameter.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.