3
votes

Obtenez la valeur asynchrone de Firestore

Je suis aux prises avec des opérations asynchrones. J'essaie simplement d'obtenir une valeur de firestore et de la stocker dans une var.

J'arrive à recevoir la valeur, je peux même la sauvegarder dans la var quand je le fais spécifiquement (utilisez la var dans la fonction get) mais Je ne semble pas gérer correctement l'attente en essayant de sauvegarder cela de manière flexible:

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');

Remarque: doc.data (). Text -> " text " est le nom du champ dans lequel ma valeur est stockée. Dois-je utiliser .value ici?

Le résultat que j'obtiens dans la console est :

info: Données du document: {text: 'Le texte correct de la base de données'}
info: Le texte correct de la base de données

Mais en utilisant helpMessage dans mon code, j'obtiens

{}

Image du bot Telegram où j'essaie d'utiliser helpMessage en réponse à la commande '/ help'.

J'ai vérifié: obtenir de la valeur à partir du cloud firestore , Firebase Firestore get () async / await , obtenir une valeur asynchrone à partir de la référence Firebase Firestore et surtout Comment renvoyer la réponse d'un appel asynchrone? . Ils traitent de plusieurs documents (en utilisant forEach), ne traitent pas de la nature asynchrone de mon problème ou (dernier cas), je ne comprends tout simplement pas la nature de celui-ci.

De plus, nodejs et firestore semble se développer rapidement et il est difficile de trouver une bonne documentation ou des exemples à jour. Tous les pointeurs sont très appréciés.


0 commentaires

3 Réponses :


3
votes

Puisque la fonction getValues ​​ renvoie une promesse, vous devez attendre la fonction getValues ​​tout en l'appelant .

Modifier getValues ​​ comme ça -

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

Ensuite, utilisez getValues ​​ comme ceci -

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);
    });
  };

Explication -

async, attend ne sont que du sucre syntaxique pour les promesses. Les fonctions async renvoient une promesse (ou AsyncFunction plus précisément) qui doit être résolue pour utiliser sa valeur incluse.

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


2 commentaires

Salut Yasser, j'ai essayé ça. Mais utiliser getValues ​​doit être dans une fonction asynchrone, ce qui n'est pas pour moi. Ainsi cela échoue. var helpMessage = await getValues ​​('configuration', 'helpMessage') ^^^^^ SyntaxError: await n'est valide que dans la fonction async


Oui, getValues ​​doit être dans une fonction asynchrone. Vous ne pouvez pas appeler getValues ​​en fonction asynchrone? Une alternative serait d'utiliser la fonction promise.then.



10
votes

Vous avez les choses dans le mauvais sens. C'est beaucoup plus facile que vous ne le pensez.

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");
}

Si une fonction renvoie une promesse (comme db.collection (...). Doc (...). Get () ), renvoyez cette promesse. Il s'agit du retour "externe" ci-dessus.

Dans le gestionnaire de promesses (à l'intérieur du rappel .then () ), renvoie une valeur pour indiquer le succès , ou une promesse rejetée pour indiquer une erreur. Il s'agit du retour "interne" ci-dessus. Au lieu de renvoyer une promesse rejetée, vous pouvez également lancer une erreur si vous le souhaitez.

Vous avez maintenant une fonction de retour de promesse. Vous pouvez l'utiliser avec .then () et .catch():

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

ou wait dans une fonction async dans un bloc try / catch, si vous préférez:

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

Si vous voulez utilisez async / await avec votre fonction getValues ​​() , vous pouvez:

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");
    }};
}


4 commentaires

Merci Tomalak! Je suppose qu'il me manque quelque chose. J'ai changé la fonction comme suggéré, puis j'ai utilisé la première recommandation que vous avez donnée (puis / catch). var helpMessage = wait getValues ​​('configuration', 'helpMessage') .then ((text) => {console.log (text); return text}) .catch ((err) => {return 'ERREUR: '+ err}); fonction asynchrone getValues ​​(nomCollection, NomDoc) {let doc = attendre db.collection (NomCollection) .doc (NomDoc) .get (); if (doc.exists) renvoie doc.data (). text; throw new Error ("No such document"); }; bot.help ((ctx) => ctx.reply ('helpMessage:', helpMessage));


D'accord et qu'est-ce qui vous manque?


Désolé, cela aurait dû faire partie de mon commentaire: la valeur ne stocke pas le résultat renvoyé par le segment texte de retour . Donc, helpMessage est toujours vide lorsqu'il est appelé dans bot.help ((ctx) => ctx.reply ('helpMessage:', helpMessage)); Remarque, le La fonction bot.help n'est déclenchée que lorsque je tape / help dans Telegram vers ce bot. Il renvoie helpMessage: (avec un espace puis rien), donc la fonction fonctionne et réagit, mais la valeur dans helpMessage semble être vide.


Dur à dire. Êtes-vous sûr que doc.data (). Text contient même le texte que vous recherchez? Peut-il y avoir une faute de frappe?



1
votes

Enfin réussi à le faire fonctionner. Merci pour la contribution 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));

Malheureusement, je ne peux pas identifier la raison exacte pour laquelle cela a fonctionné. Quelques petites corrections (virgule manquée dans le console.log) et le formatage m'ont certainement aidé à comprendre la structure. J'espère que quelqu'un d'autre trouvera cela utile, en commençant à jouer avec le nœud et la base de feu.


0 commentaires