【问题标题】:How to load 2 different Firestore docs in one 'onUpdate' Cloud Function?如何在一个“onUpdate”云功能中加载 2 个不同的 Firestore 文档?
【发布时间】:2023-03-11 06:35:01
【问题描述】:

我正在尝试创建一个“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:电话未定义

【问题讨论】:

  • 这还不是Minimum Reproducible Example,所以很难回答。 newFunction() 的代码是什么?您能否提供您的数据库布局的图片或其他说明?
  • 我不确定我是否理解。这是整个功能。我会更新数据库的图片。
  • 我需要获取电话变量(1111111111)和状态(警报)变量,并使用它们通过 nodemailer 发送电子邮件。我在 if 语句中测试了 nodemailer 代码,它工作正常。我只是无法读取电话变量。谢谢!
  • 我指的是.document(newFunction())。通常,我希望其中包含您要匹配的path to the documents
  • 我修好了。在我的代码中不是这样。不知道那是怎么发生的。对此感到抱歉。

标签: firebase google-cloud-firestore google-cloud-functions firebase-admin onupdate


【解决方案1】:

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

  • promise 的处理并没有真正按照您期望的方式传递数据 - 特别是,变量 phone 和 email 只存在于一个 promise 处理程序中,它们不是全局范围的,所以 phoneemail 没有被传递到承诺链中。

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

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

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() 或对该调用执行await(并使整个函数async),因此您需要更仔细地查看。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-11
    • 2019-06-02
    • 2021-11-18
    • 1970-01-01
    • 2020-10-29
    • 1970-01-01
    • 2018-08-01
    • 2020-02-01
    相关资源
    最近更新 更多