【发布时间】:2018-11-09 13:28:44
【问题描述】:
我有一个由 http 请求触发的云功能,它打算执行以下操作:
- 根据查询获取一定数量的文档。
- 对查询的每个文档执行一次读取操作。
- 从 (2) 中获取新文档后,执行一些读/写操作(从子集合中删除,将文档添加到另一个子集合,并更新根集合上的文档)。
因此我需要等待(2)和(3)循环然后执行批处理操作的东西。
以下是我目前拥有的代码,当我在本地测试该功能时它可以正常工作。但是我无法将它部署到 Firebase,因为它有诸如“每次都必须返回一个承诺”和“避免嵌套承诺”之类的承诺错误。
exports.finishEvents = functions.https.onRequest((req, res) => {
const eventsRef = admin.firestore().collection('events');
var currentTime = new Date().getTime();
var currentTimeMinus1h = currentTime - 3600000;
console.log('----- finishEvents started -----')
const queryRef = eventsRef.where('finished', '==', false).where('date', '<=', new Date(currentTimeMinus1h)).get().then(function(querySnapshot){
if (querySnapshot.size > 0) {
querySnapshot.forEach(function(doc) {
var owner_id = doc.data().owner_id;
var event_id = doc.id;
console.log(owner_id, event_id);
var userEventOwnerGoingRef = admin.firestore().collection("user_events").doc(owner_id).collection('going').doc(event_id);
userEventOwnerGoingRef.get().then(doc2 => {
if (!doc2.exists) {
console.log('No such document!');
} else {
console.log('Document data:', doc2.data());
var goingIds = doc.data().going_ids;
console.log('GOING IDS', goingIds);
var batch = admin.firestore().batch();
for (var userId in goingIds) {
if (goingIds.hasOwnProperty(userId)) {
console.log(userId + " -> " + goingIds[userId]);
var eventRef = admin.firestore().collection("events").doc(event_id);
var userEventGoingRef = admin.firestore().collection("user_events").doc(userId).collection('going').doc(doc2.id);
var userEventAttendedRef = admin.firestore().collection("user_events").doc(userId).collection('attended').doc(doc2.id);
batch.set(userEventAttendedRef, doc2.data());
batch.delete(userEventGoingRef)
if (userId == doc2.data().owner_id) batch.update(eventRef, {finished: true});
}
}
batch.commit().then(function () {
return res.status(200).send("Done.");
});
}
})
.catch(err => {
console.log('Error getting userEventOwnerGoingRef', err);
return res.status(200).send("Finished.");
});
});
} else {
console.log("No events found");
return res.status(200).send("Finished.");
}
})
.catch(err => {
console.log('Error getting events', err);
return res.status(200).send("Finished.");
});
});
当我在本地对其进行测试时,即使作业已完成,我也会收到一条错误提示
UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Can't set headers after they are sent.
我可以看到我正在发送原始查询的每个文档的结果,我只需要发送一次结果即可完成云功能。
我想我需要返回承诺,然后在步骤 (2) 和 (3) 完成后执行我的所有内容的批处理事务。然而,这是我第一次使用 javascript,我正在为此苦苦挣扎。任何帮助将不胜感激。
【问题讨论】:
-
你不能忽视来自
batch.get().then()的承诺。 -
正如@Doug 所说,您需要处理每一个承诺。另外,如果可能,我建议尝试将每次读取和写入都作为事务进行。
-
是的,感谢您的评论。如果可能的话,我真的很感激一个完整的答案。
标签: node.js firebase google-cloud-firestore google-cloud-functions