0

I have got a function in an API library that calls firestore and gets data back. This part works fine:

export const getUserByReferrerId = async id => {
  let doc = await firestore
    .collection(FIRESTORE_COLLECTIONS.USERS)
    .where('grsfId', '==', id)  
    .get()  
    .then(querySnapshot => {
      if (!querySnapshot.empty) {
        console.log ("we found a doc");
        // use only the first document, but there could be more
        const snapshot = querySnapshot.docs[0];
        console.log ("snapshot", snapshot.id);
        return snapshot.id  // uid of the user
      }
    });
}

I am calling this library from a component. I have another function that runs on a button click. I cannot figure out how to get the value from the async api call.

I have tried this - a promise appears when I console.log the return:

testCreditFunction = (id) => {
    let uid = getUserByReferrerId(id).then(doc => { 
        console.log("uid1", doc);    
    });
}

I have also tried this - log shows null for uid.

testCreditFunction = (id) => {
    let uid = '';
    
    (async () => {
        uid = await getUserByReferrerId(id);
        console.log ("uid in the function", uid);
    })();
}

I have seen this question asked a few times and I have tried several of the answers and none are working for me. The odd thing is that I have done this same thing in other areas and I cannot figure out what the difference is.

AGE
  • 3,752
  • 3
  • 38
  • 60
AdamCodes716
  • 155
  • 2
  • 11
  • 1
    You assign to `doc` but do not show any code that would `return` anything from `getUserByReferrerId`. For a caller to "get" something via `await` or `.then`, you need to return at all levels. – crashmstr Dec 03 '20 at 14:14
  • you need to return ```doc``` in ```getUserByReferrerID``` method. Right now it's not returning anything, and that's probably why you're getting a promise returned instead of the value. – Michael Dec 03 '20 at 14:19
  • You get a `Promise` because the function is `async` and it has an `await`. That happens without needing to `return` anything. But to get a value out, you need to `return` that value. If you return a value, you *still* get a promise, but a promise that resolves to the value (with `.then` or `await`) – crashmstr Dec 03 '20 at 14:23
  • Duplicate of [Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference](https://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron) and [How do I return the response from an asynchronous call?](https://stackoverflow.com/q/14220321/8376184) – FZs Dec 03 '20 at 19:43

2 Answers2

1

One thing I notice right off the bat is that you're mixing async/await & .then/.error. While it's not strictly forbidden it definitely makes things more difficult to follow.

As others have mentioned in the comments, you need to make a return for the promise to resolve (complete). Here's how you might write getUserByReferrerId (using async/await).

const getUserByReferrerId = async id => {
  const usersRef = firestore.collection('users');
  const query = usersRef.where('grsfId', '==', id);

  const snapshot = await query.get();
  if (snapshot.empty) {
   console.log('no doc found');
   return;
  }

  console.log('doc found');
  const doc = snapshot.docs[0]; // use first result only (there might be more though)
  return doc.id
}

You'll notice how I split up the query building steps from the snapshot request. This was intentional as the only promised function in this is the get request.

Using this getUserByReferrerID can be done with a simple await. Just be sure to check that the result isn't undefined.

const userID = await getUserByReferrerId('someid')

if (!userID) {
  console.log('user not found');
}

console.log(`User ID is ${userID}`);
  

p.s - I would recommend renaming the function to getUserIdByReferrerId to more accurately reflect the fact that you're returning an ID and not a user doc. Alternatively, you can return the user object and leave the name as is.

vivalldi
  • 511
  • 2
  • 14
  • Thanks so much for this! I did try something similar before and ran into an issue where it didn't like the await in the calling area. Here is the button click code: – AdamCodes716 Dec 03 '20 at 18:05
  • I see the problem - the calling function also need async around it: (async () => { const userID = await getUserByReferrerId(id) – AdamCodes716 Dec 03 '20 at 18:17
  • Yup, I purposefully didn't wrap it in a `(async ...)()` because I wasn't sure if you would have been using it in an async function already – vivalldi Dec 03 '20 at 18:46
1

Change your funtion to this.

export const getUserByReferrerId = async id => {
  return await firestore
  .collection(FIRESTORE_COLLECTIONS.USERS)
  .where('grsfId', '==', id)  
  .get();
}

Try getting data this way.

 testCreditFunction = (id) => {

 let querySnapshot = '';
        
    (async () => {
      querySnapshot = await getUserByReferrerId(id);
      const snapshot = querySnapshot.docs[0];
      console.log ("snapshot", snapshot.id);
  })();
Rajitha Udayanga
  • 1,559
  • 11
  • 21