skip to Main Content

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.

3

Answers


  1. Chosen as BEST ANSWER

    Finally managed to get it working. Thanks for the input Tomalak!

    getValues(help.collectionName, help.docName)
      .then((text) => {
        console.log(text);
        help.message = text;
       })
      .catch((err) => { console.log("Error: ", err); });
    
    function getValues(collectionName, docName) {
      return db.collection(collectionName).doc(docName).get().then((doc) => {
        if (doc.exists) {
          return doc.data().text;
        }
        else {
          return Promise.reject("No such document");
        }});
      }
    
    bot.help((ctx) => ctx.reply(help.message));
    

    Unfortunately, I can not pin-point the exact reason this worked. Some little fixes (missed comma in the console.log) and formatting definitely helped me understanding the structure though. Hope someone else finds this useful, when starting to play around with node and firebase.


  2. 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

    Login or Signup to reply.
  3. 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");
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search