0

I have a function that should return a list of documents data from a given collection.

function _getPrevActivity(){

let historyCollectionRef =  firestore.collection("/users/RSgNDLPxT2aAERQutXEEyhHHJYk1/agreements/DkRdZ5kHi2g7MlBV3Kjq/test/test-something/records/15/history");
let value = [];
let wait;
    historyCollectionRef.orderBy('timeStamp').onSnapshot(querSnap => {
    querSnap.forEach(doc => {
        value.push(doc.data())
        console.log(value.length, " length")

        })
    console.log(value)
    return value;

    });

return value;

}

This functions is always returning [] and later executing the firestore query.

PS: I am new to Node env, there might be something wrong with how I wrote the function as well.

kt14
  • 838
  • 15
  • 25
  • `onSnapshot` returns immediately, which means your function will return `value` unchanged from its original value. The callback you pass on `onSnapshot` will be invoked some time later, when the results of the query is ready. In other words, you can't just make a function return a value produced asynchronously. https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call – Doug Stevenson Apr 26 '18 at 16:12
  • Also bear in mind that the callback to onSnapshot will be invoked possibly many times, once for each change to the document. If you want just one value, use `get()` instead. – Doug Stevenson Apr 26 '18 at 16:24
  • Well thats just sad, so there is no way to achieve this without changing firestore api ? I have changed `onSnapshot` to `get`. – kt14 Apr 26 '18 at 17:03
  • Asynchronous programming with promises (like the ones returned by `get()`) is extremely common in javascript and node. You really can't avoid it. https://medium.com/google-developers/why-are-the-firebase-apis-asynchronous-e037a6654a93 – Doug Stevenson Apr 26 '18 at 17:05
  • Well it makes sense after reading through the article, just need to refactor on my end – kt14 Apr 26 '18 at 17:21

1 Answers1

0

You are doing the classic mistake of handling asynchronous calls like you do with synchronous programming.

I restructured your code as follows:

function _getPrevActivity() {
      let value = [];
      let wait;
      const path = "/users/RSgNDLPxT2aAERQutXEEyhHHJYk1/agreements/DkRdZ5kHi2g7MlBV3Kjq/test/test-something/records/15/history";

      return firestore.collection(path).orderBy('timeStamp')
        .onSnapshot(querSnap => {
          querSnap.forEach(doc => {
            value.push(doc.data())
            console.log(value.length, " length")
          });
          console.log(value)
          return value;
        }).catch(error => {
          console.log(error);
          return value;
        });
    }

    // calling function
    function otherFunc() {
      _getPrevActivity().then(value => {
        // do something with value...
        // value will not be an empty array now
        console.log(value);
      }).catch(console.log);
    }

The mistake you are doing here is that you can't really return a value from the anonymous function querSnap => {... unless you also return the enclosing promise from the function from which you want the value returned.

Also, to access the value from the return of an async call will require the use of the then() clause which I have added to the code below.

Utkarsh Bhatt
  • 1,536
  • 2
  • 14
  • 23
  • I tried this but in `otherFunc` is throwing error, `_getPrevActivity)(...).then is not a function` – kt14 Apr 26 '18 at 17:44
  • Are you using the correct syntax? It is `_getPrevActivity().then(value)` and not `_getPrevActivity)(...).then` what you wrote here in the comment. – Utkarsh Bhatt Apr 26 '18 at 18:18