Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get async value from firestore

I am struggling with async operations. I am trying to simply get a value from firestore and storing it in a var.

I manage to receive the value, I can even save it in the var when I do that specifically (use the var within the get function) but I don't seem to manage the await properly when trying to save this in a flexible way:

async function getValues(collectionName, docName,) {
console.log("start")
var result;
var docRef = await db.collection(collectionName).doc(docName).get()
  .then(//async// (tried this as well with async) function (doc) {
    if (doc.exists) {
      console.log("Document data:", doc.data());
      result = doc.data().text;
      console.log(result);
      return //await// (this as well with async) result;
    } else {
      // doc.data() will be undefined in this case
      console.log("No such document!");
      result = "No such document!";
      return result;
    }
    console.log("end");
  }).catch (function (err) {
    console.log('Error getting documents', err);
  });
};

helpMessage = getValues('configuration','helpMessage');

Note: doc.data().text -> "text" is the name of the field where my value is stored in. Do I have to use .value here?

The result I get in the console is:

info: Document data: { text: 'The correct text from the database' }
info: The correct text from the database

But using helpMessage in my code I get

{}

Image from the Telegram bot where I am trying to use the helpMessage as a response to the '/help' command.

I have checked: getting value from cloud firestore, Firebase Firestore get() async/await, get asynchronous value from firebase firestore reference and most importantly How do I return the response from an asynchronous call?. They either deal with multiple documents (using forEach), don't address the async nature of my problem or (last case), I simply fail to understand the nature of it.

Additionally, both nodejs and firestore seems to be developing rapidly and finding good, up-to-date documentation or examples is difficult. Any pointers are much appriciated.

like image 845
RobSteward Avatar asked Dec 01 '22 14:12

RobSteward


2 Answers

You have things the wrong way around. It's much easier than you think it is.

function getValues(collectionName, docName) {
    return db.collection(collectionName).doc(docName).get().then(function (doc) {
        if (doc.exists) return doc.data().text;
        return Promise.reject("No such document");
    }};
}

If a function returns a promise (like db.collection(...).doc(...).get()), return that promise. This is the "outer" return above.

In the promise handler (inside the .then() callback), return a value to indicate success, or a rejected promise to indicate an error. This is the "inner" return above. Instead of returning a rejected promise, you can also throw an error if you want to.

Now you have a promise-returning function. You can use it with .then() and .catch():

getValues('configuration','helpMessage')
    .then(function (text) { console.log(text); })
    .catch(function (err) { console.log("ERROR:" err); });

or await it inside an async function in a try/catch block, if you like that better:

async function doSomething() {
    try {
        let text = await getValues('configuration','helpMessage');
        console.log(text);
    } catch {
        console.log("ERROR:" err);
    }
}

If you want to use async/await with your getValues() function, you can:

async function getValues(collectionName, docName) {
    let doc = await db.collection(collectionName).doc(docName).get();
    if (doc.exists) return doc.data().text;
    throw new Error("No such document");
}
like image 161
Tomalak Avatar answered Dec 04 '22 09:12

Tomalak


Since getValues function returns a promise, you need to await getValues function while calling it.

Change getValues like so -

function getValues(collectionName, docName,) {
  console.log("start")
  var result;
  return db.collection(collectionName).doc(docName).get()
    .then(function (doc) {
      if (doc.exists) {
        console.log("Document data:", doc.data());
        result = doc.data().text;
        console.log(result);
        return result;
      } else {
        // doc.data() will be undefined in this case
        console.log("No such document!");
        result = "No such document!";
        return result;
      }
    }).catch (function (err) {
      console.log('Error getting documents', err);
    });
  };

Then use getValues like so -

helpMessage = await getValues('configuration','helpMessage');

Explanation -

async, await are just syntactic sugar for Promises. async functions return a promise (or AsyncFunction more accurately) which needs to be resolved to use its enclosed value.

See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

like image 33
Yasser Hussain Avatar answered Dec 04 '22 11:12

Yasser Hussain