如何在一个 'onUpdate' Cloud Function 中加载 2 个不同的 Firestore 文档?
How to load 2 different Firestore docs in one 'onUpdate' Cloud Function?
我正在尝试创建一个 "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))
);
});
所以我想在这两张图片中获取 phone 号码和状态
返回的错误:
ReferenceError: phone is not defined
有两件事并没有按照您预期的方式工作,从而导致了您的问题:
promise 的处理并没有真正按照您期望的方式传递数据——特别是,变量 phone 和 email 只存在于一个 promise 处理程序中,它们不是全局的在范围内,因此 phone
和 email
不会沿着承诺链向下传递。
您实际上不需要阅读第二个文档,因为内容是在函数本身中传递给您的。这实际上大大简化了您正在做的整体事情,并使处理第一点变得几乎微不足道,因为您可以跳过第二个数据库调用。
看看这段代码,为了清楚起见,我省略了消息传递代码,只保留了大部分日志消息:
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
参数。然后我们获取包含我们需要的内容的文档——在树的更高级别。一旦该文档被 returned,我们只需对其进行处理并与来自 doc2 的数据相结合。现在所有字段都已定义(当然,假设数据库对象格式正确)。
如果明显的日志消息是,您的消息代码将被重新插入。
最后,info
列表我认为现在没有必要,所以我将其删除。相反,我建议您在根据现有数据构建消息本身时构建所需的内容。也就是说,您的原始代码无论如何都没有正确访问它(即,作为列表),并且可能让您更加困惑。
最后,我没有解决 Nodemailer 模块的使用问题,因为问题主要集中在未定义的字段上,但我怀疑您的原始代码可能也不完全正确——因为它也不完全正确 return 来自 sendMail()
的承诺或对该调用执行 await
(并使整个函数 async
),因此您需要更仔细地查看它。
我正在尝试创建一个 "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))
);
});
所以我想在这两张图片中获取 phone 号码和状态 返回的错误:
ReferenceError: phone is not defined
有两件事并没有按照您预期的方式工作,从而导致了您的问题:
promise 的处理并没有真正按照您期望的方式传递数据——特别是,变量 phone 和 email 只存在于一个 promise 处理程序中,它们不是全局的在范围内,因此
phone
和email
不会沿着承诺链向下传递。您实际上不需要阅读第二个文档,因为内容是在函数本身中传递给您的。这实际上大大简化了您正在做的整体事情,并使处理第一点变得几乎微不足道,因为您可以跳过第二个数据库调用。
看看这段代码,为了清楚起见,我省略了消息传递代码,只保留了大部分日志消息:
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
参数。然后我们获取包含我们需要的内容的文档——在树的更高级别。一旦该文档被 returned,我们只需对其进行处理并与来自 doc2 的数据相结合。现在所有字段都已定义(当然,假设数据库对象格式正确)。
如果明显的日志消息是,您的消息代码将被重新插入。
最后,info
列表我认为现在没有必要,所以我将其删除。相反,我建议您在根据现有数据构建消息本身时构建所需的内容。也就是说,您的原始代码无论如何都没有正确访问它(即,作为列表),并且可能让您更加困惑。
最后,我没有解决 Nodemailer 模块的使用问题,因为问题主要集中在未定义的字段上,但我怀疑您的原始代码可能也不完全正确——因为它也不完全正确 return 来自 sendMail()
的承诺或对该调用执行 await
(并使整个函数 async
),因此您需要更仔细地查看它。