javascript - 函数返回未定义的、预期的 Promise 或值,并且无法使用云函数从 Firebase 数据库中删除旧数据
问题描述
我正在尝试删除数据库上超过 12 小时的多个节点。我正在使用 pub/sub 函数来触发此事件。我不知道我的代码是否实际上循环遍历所有节点,因为我没有使用特定的onWrite
数据库onCreate
触发器。这是数据库的图像示例
这是发布/订阅代码
exports.deletejob = functions.pubsub.topic('Oldtask').onPublish(() => {
deleteOldItem();
})
和 deleteOldItem 函数
function deleteOldItem(){
const CUT_OFF_TIME = 12 * 60 * 1000; // 12 Hours in milliseconds.
//var ref = admin.database().ref(`/articles/${id}`);
const ref = admin.database().ref(`/articles`);
const updates = {};
ref.orderByChild('id').limitToLast(100).on('value', function (response) {
var index = 0;
response.forEach(function (child) {
var element = child.val();
const datetime = element.timestamp;
const now = Date.now();
const cutoff = now - datetime;
if (CUT_OFF_TIME < cutoff){
updates[element.key] = null;
}
});
//This is supposed to be the returened promise
return ref.child(response.key).update(updates);
});
如果我做错了什么,我很想知道。发布/订阅是由已在谷歌云调度程序上设置的 JobScheduler 触发的
解决方案
您的代码中有几个问题给您带来了麻烦。
- 对承诺的处理不正确。特别是,您的顶级函数实际上从未返回过承诺,它只是调用了
deleteOldItems()
. - 您应该使用 promise 形式
once()
而不是on()
使用回调调用,因为在这种情况下您不想安装侦听器,您只需要一次结果,并且希望将其作为 promise 链的一部分进行处理。 - 要删除节点,您应该调用
remove()
对该节点的引用。它还会生成一个承诺供您在此处使用。 - 您没有正确计算以毫秒为单位的 12 小时,您以毫秒为单位计算了 12 分钟 :)
这就是我想出的。它使用 http 函数而不是 pubsub 函数以及为我的测试添加日志语句,但是您需要的修改应该是微不足道/显而易见的(只需更改原型并删除之后的响应deleteOldItems
,但请确保您继续返回)的结果deleteOldItems()
:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
function deleteOldItems() {
const CUT_OFF_TIME = 12 * 60 * 60 * 1000; // 12 Hours in milliseconds.
const ref = admin.database().ref('/articles');
return ref.orderByChild('id').limitToLast(100).once('value')
.then((response) => {
const updatePromises = [];
const now = Date.now();
response.forEach((child) => {
const datetime = child.val().timestamp;
const cutoff = now - datetime;
console.log(`processing ${datetime} my cutoff is ${CUT_OFF_TIME} and ${cutoff}`);
if (CUT_OFF_TIME < cutoff){
updatePromises.push(child.ref.remove())
}
});
return Promise.all(updatePromises);
});
}
exports.doIt = functions.https.onRequest((request, response) => {
return deleteOldItems().then(() => { return response.send('ok') });
}
虽然我尚未对其进行测试,但我很确定这将包含在您对云调度程序的原始函数调用中:
exports.deletejob = functions.pubsub.topic('Oldtask').onPublish(() => {
return deleteOldItems();
})
当然,这仍然比您需要的复杂,因为 order byid
在这里并没有真正为您带来任何好处。相反,为什么不只使用查询返回截止时间之前最早的项目(例如,正是您要删除的项目)?我也切换到limitToFirst
确保最早的条目被丢弃,这看起来更自然并确保公平:
function deleteOldItems() {
const cutOffTime = Date.now() - (12 * 60 * 60 * 1000); // 12 Hours earlier in milliseconds.
const ref = admin.database().ref('/articles');
return ref.orderByChild('timestamp').endAt(cutOffTime).limitToFirst(100).once('value')
.then((response) => {
const updatePromises = [];
response.forEach((child) => {
updatePromises.push(child.ref.remove())
});
return Promise.all(updatePromises);
});
}
如果您对多个项目执行此操作,当然,您可能希望在时间戳字段上添加索引,以便范围查询更有效。
推荐阅读
- python - EWS exchangelib python:无法使用“.body”属性提取电子邮件内容
- c - 我的程序意外停止运行,并且无法释放变量
- node.js - NODEJS + WS 库 = 缓冲区分配错误
- javascript - iText 样式数组上的 FabricJS lineHeight
- python - python / opencv3双阈值(上下)
- javascript - 在 HTML 页面上显示 SVG
- java - 休眠未保存外键
- java - 无法在 Http 拦截器 Java/Spring 中设置对象
- c# - 创建“然后我向下滚动 (x,y)”场景 Visual Studio Selenium Specflow
- javascript - 获取id数组中所有匹配id的元素