首页 > 解决方案 > Firebase 云函数错误:某些值显示为未定义?

问题描述

我正在为学生设计游戏体验。游戏就像危险游戏一样,随着学生在游戏中的进步,它会将数据写入实时数据库。在游戏结束时,我想向学生发送一封电子邮件,确认他们已经完成了他们的分数和完成时间/日期。

为此,我在云函数中设置了以下代码。但是,当我从触发器运行代码时,我从数据库中读取的一些值显示为未定义 - 这意味着电子邮件中不存在某些数据。这里发生了什么???

   'use strict';

    const functions = require('firebase-functions');
    const admin = require('firebase-admin');
    const nodemailer = require('nodemailer');

    admin.initializeApp({
       credential: admin.credential.applicationDefault(),
       databaseURL: 'https://[MY DATABASE URL]/'
    });

     const gmailEmail = functions.config().gmail.email;
     const gmailPassword = functions.config().gmail.password;
     const mailTransport = nodemailer.createTransport({
        service: 'gmail',
        auth: {
           user: gmailEmail,
           pass: gmailPassword,
         },
       });       

         var email;
         var exitTime;
         var name;
         var userScore;

 exports.gameDoneNotice=functions.database.ref("USERS/{termDate}/GameData/{myUID}/ExitDateTime")
  .onCreate(async (snapshot, context) => {

         const myNumber = context.params.myUID; 
         const myRotation = context.params.termDate; 

            var adminDB = admin.database();

            exitTime = snapshot.val();

            var aRef = adminDB.ref("USERS/" + myRotation + "/GameData/" + myNumber + "/");
            aRef.on("value", (snapshot) => {
                email = snapshot.child("eMail").val();
                name = snapshot.child("Name").val();
                userScore = snapshot.child("User Score").val();
            });

            var emailsaad = "MYEMAIL@EMAIL.COM";

            console.log(myNumber);
            console.log(myRotation);
            console.log(userScore);
            console.log(name); 


        const APP_NAME = 'WCM-Q DeLib eLearning';        

        const mailOptions = {
             from: `${APP_NAME} <noreply@firebase.com>`,
             to: email,
             bcc: emailsaad,
            };  


         mailOptions.subject = `Welcome to ${APP_NAME}!`;
         mailOptions.html = `<h3>Dear, ${name}</h3><p>Thank you for completing the Medicine Clerkship EBM game.</p><hr><h4>Your Score: <font color="red">${userScore}</font></h4><h4>Game Completion  Time/Date: <font color="green">${exitTime}</font></h4><hr><p>If you have any questions about the game or your EBM project in this clerkship, don’t hesitate to ask for clarification. Otherwise, your next step is to begin to prepare with your group for your presentation.</p>`;


         try {
             await mailTransport.sendMail(mailOptions);
             console.log("eMail was a success");
           } catch(error) {
             console.error('Something has gone horribly wrong, bro!', error);
           }
            return null;

            });

我希望我应该能够从数据库中读取电子邮件、userScore 等所需的值,并在发送之前将它们包含在 mailOptions 中。但是,当我在触发后收到电子邮件时,从数据库读取的所有值都是“未定义的”。

标签: firebasefirebase-realtime-databasegoogle-cloud-functions

解决方案


而不是使用on()设置侦听器“针对特定位置的数据更改”的once()方法,您需要使用“仅侦听指定事件类型的一个事件”并返回 Promise 的方法。然后,您将能够await使 Cloud Function 等待,直到 resolve 返回的 promiseonce()并返回其结果。

因此,您应该如下修改您的代码:

exports.gameDoneNotice = functions.database
  .ref('USERS/{termDate}/GameData/{myUID}/ExitDateTime')
  .onCreate(async (snapshot, context) => {
    const myNumber = context.params.myUID;
    const myRotation = context.params.termDate;

    var adminDB = admin.database();

    exitTime = snapshot.val();

    var aRef = adminDB.ref(
      'USERS/' + myRotation + '/GameData/' + myNumber + '/'
    );

    try {
      const snapshot = await aRef.once('value');
      const email = snapshot.child('eMail').val();
      const name = snapshot.child('Name').val();
      const userScore = snapshot.child('User Score').val();

      const emailsaad = 'MYEMAIL@EMAIL.COM';

      console.log(myNumber);
      console.log(myRotation);
      console.log(userScore);
      console.log(name);

      const APP_NAME = 'WCM-Q DeLib eLearning';

      const mailOptions = {
        from: `${APP_NAME} <noreply@firebase.com>`,
        to: email,
        bcc: emailsaad
      };

      mailOptions.subject = `Welcome to ${APP_NAME}!`;
      mailOptions.html = `<h3>Dear, ${name}</h3><p>Thank you for completing the Medicine Clerkship EBM game.</p><hr><h4>Your Score: <font color="red">${userScore}</font></h4><h4>Game Completion  Time/Date: <font color="green">${exitTime}</font></h4><hr><p>If you have any questions about the game or your EBM project in this clerkship, don’t hesitate to ask for clarification. Otherwise, your next step is to begin to prepare with your group for your presentation.</p>`;

      await mailTransport.sendMail(mailOptions);
      //Here, actually you could also do return mailTransport.sendMail(mailOptions); , see the video mentioned below

    } catch (error) {
      console.error('Something has gone horribly wrong, bro!', error);
    }
  });

您可以观看 Doug Stevenson 的官方Firebase 视频系列,其中解释了所有这些要点。特别是关于“JavaScript Promises”的 3 个视频和关于 async/await 的视频:https ://www.youtube.com/watch?v=Jr7pDZ1RAUg


推荐阅读