0

我正在尝试制作一个“onUpdate”函数来加载已更新的文档。然后我想使用通配符接收到的数据加载另一个文档。总而言之,我想访问已更新的文档以及同一集合中的另一个文档。

我想要:/userProfiles/{doc1}/employees/{doc2}/userProfiles/{doc1}

我可以同时获取它们,但是当我尝试使用其中的数据时,它不会读取以前的数据并给我一个ReferenceError.

最终目标是使用这两个文档通过 nodemailer 发送电子邮件。谢谢你的帮助。


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

exports.testLog = functions.firestore
  .document('/userProfiles/{doc1}/employees/{doc2}')
  .onUpdate((change, context) => {
    var info = [];
    const doc1 = context.params.doc1;
    const doc2 = context.params.doc2;

    const db = admin.firestore();

    return (
      db
        .collection("userProfiles")
        .doc(`${doc1}`)
        .get()
        .then(doc => {
          var email = doc.data().email;
          var phone = doc.data().phone;

          info.push(doc.data());

          console.log(email, phone); // sees and gets info

          return email, phone;
        }),
      db
        .collection("userProfiles")
        .doc(`${doc1}`)
        .collection(`employees`)
        .doc(`${doc2}`)
        .get()
        .then(doc => {
          info.push(doc.data());

          var Status = doc.data().Status;

          console.log(phone, `${Status}`); //phone is undefined

          if (`${Status}` === "Alarm") {
            // replace with variables from the users settings page

            console.log(`${info.phone}`); // phone is undefined

            let transporter = nodemailer.createTransport({
              host: "smtp.gmail.com",
              port: 587,
              secure: false, 
              auth: {
                user: "xxxxxx@gmail.com",
                pass: "xxxxxxxxxx"
              }
            });

            // send mail with defined transport object
            let mailOptions = {
              from: '"Fred Foo " <foo@example.com>', 
              to: `${info.phone}`,  // tried phone as well
              subject: "Hello ✔", 
              text: "216+?", 

            };

            transporter.sendMail(mailOptions, error => {
              if (error) {
                return console.log(error);
              } else {
                return console.log("message sent");
              }
            });
          }

          console.log(Status);
          // return
          return console.log("im after the if statement. No alarm triggered");
        })

        .then(message => console.log(message.sid, "success"))
        .catch(err => console.log(err))
    );
  });

火库

子集合

所以我想获取这两张图片中的电话号码和状态返回的错误:

ReferenceError:电话未定义

4

1 回答 1

2

有两件事不能完全按照您预期的方式工作,从而导致您的问题:

  • Promise 的处理并没有真正按照您期望的方式传递数据——特别是,变量 phone 和 email 只存在于一个 Promise 处理程序中,它们在范围内不是全局的,因此phone不会email沿着 Promise 链传递.

  • 您实际上不需要阅读第二个文档,因为内容是在函数本身中传递给您的。这实际上大大简化了您正在做的整体事情,并且使处理第一点几乎是微不足道的,因为您可以跳过第二个数据库调用。

请看这段代码,为了清楚起见,我省略了消息传递代码,并且只保留了大部分日志消息:

exports.firestoreOnUpdateTest = functions.firestore
    .document('/userProfiles/{doc1}/employees/{doc2}')
    .onUpdate((change, context) => {
  // var info = []; I have removed this list, it is not necessary
  const doc1 = context.params.doc1;
  // no need to get the doc2 parameter, as we are handed the doc itself by the function call.

  const doc2content = change.after.data();

  const db = admin.firestore();

  return (
    db
      .collection("userProfiles")
      .doc(`${doc1}`)
      .get()
      .then(doc => {
        const doc1content = doc.data();
        const email = doc1content.email;
        const phone = doc1content.phone;

        console.log(email, phone); // sees and gets info

        console.log(`No need to fetch doc2, as I already have it: ${JSON.stringify(doc2content)}`);
        const Status = doc2content.Status;

        console.log(`email for user is still: ${email}`); // email is now defined
        console.log(phone, `${Status}`); // phone is now defined

        if (`${Status}` === "Alarm") {
          console.log(`${phone}`); // phone is now defined

          return console.log('message would be sent here - code omitted')
        }

        console.log(Status);

        return console.log("im after the if statement. No alarm triggered");
      })
      .catch(err => console.error(err))
  );
});

在新版本中,我们只存储触发我们的文档中的内容,包括Status参数。然后,我们在树的更高级别获取包含我们需要的内容的文档。返回该文档后,我们只需对其进行处理并与来自 d​​oc2 的数据相结合。现在所有字段都已定义(当然,假设数据库对象格式正确)。

如果明显的日志消息是,您的消息代码将被重新插入。

最后,info我认为现在不需要的列表,所以我删除了它。相反,我建议您在根据现有数据构建消息本身时构建您需要的内容。也就是说,您的原始代码无论如何都没有正确访问它(即作为列表),并且可能进一步混淆了您。

最后,我没有解决 Nodemailer 模块的使用问题,因为问题主要集中在未定义的字段上,但我怀疑您的原始代码也可能不完全正确——因为它既不会返回承诺,也不会sendMail()执行an awaiton that call (并制作整个函数async),因此您需要更仔细地查看它。

于 2019-10-28T18:00:20.530 回答