使用Firebase Cloud函数删除旧数据



我需要定期从Firebase中删除旧数据。我找到了这个解决方案,但一直未能使其发挥作用。

终端告诉我functions[deleteOldItems(us-central1)]: Successful update operation.,但数据没有被删除。

这就是我所做的:

const functions = require('firebase-functions');
exports.deleteOldItems = functions.database.ref('/nodeThatContainsDataToBeDeleted')
.onWrite((change, context) => {
var ref = change.after.ref.parent; // reference to the items
var now = Date.now();
var cutoff = now - 2 * 60 * 60 * 1000;
var oldItemsQuery = ref.orderByChild('timestamp').endAt(cutoff);
return oldItemsQuery.once('value', function(snapshot) {
// create a map with all children that need to be removed
var updates = {};
snapshot.forEach(function(child) {
updates[child.key] = null
});
// execute all updates in one go and return the result to end the function
return ref.update(updates);
});
});

timestamp639915248.124176(来自Swift(

数据库结构:

root : {
"nodeThatContainsDataToBeDeleted" : {
"-r5tyfX9FGC0glhgf78Ia" : {
"company" : "CompanyCo",
"name" : "Sam",
"phone" : "1212",
"imageURL" : "https://firebasestorage.googleapis.com/imageurl",
"timestamp" : 6.39915248124176E8
}
},
}

当您在后台触发的云函数(在您的情况下是once()update()方法(中执行异步操作时,您必须返回一个Promise,这样云函数就会等待这个Promise解析以终止。更多信息在三个官方视频标题";学习JavaScript承诺"(第2部分和第3部分特别关注背景触发的云功能,但之前确实值得看第1部分(。

通过执行oldItemsQuery.once('value', function(snapshot) {...}),您实际上使用了once()方法的回调版本。

为了正确地链接不同的promise并在回调中返回此链,您需要使用promise版本,如下所示:

exports.deleteOldItems = functions.database.ref('/nodeThatContainsDataToBeDeleted')
.onWrite((change, context) => {
var ref = change.after.ref.parent; // reference to the items
var now = Date.now();
var cutoff = now - 2 * 60 * 60 * 1000;
var oldItemsQuery = ref.orderByChild('timestamp').endAt(cutoff);
return oldItemsQuery.once('value')
.then(snapshot => {
// create a map with all children that need to be removed
var updates = {};
snapshot.forEach(function (child) {
updates[child.key] = null
});
// execute all updates in one go and return the result to end the function
return ref.update(updates);
});
});

这个答案建立在@RenaudTarnec的答案之上。

自2015年以来,JavaScript和Firebase SDK已经取得了长足的进步,因此在复制/使用StackOverflow上的旧代码示例时要小心这一点。您链接的解决方案还链接到functions-samplesrepo,其中的示例代码一直保持最新的现代功能。

正如Renaud所述,您需要切换到只使用Promise版本的once()侦听器,而不是使用回调。虽然您的代码确实按预期返回了Promise,但当前回调没有正确插入到Promise链中,这意味着您的云函数没有等待回调中的代码完成。链接的例子是在2015年写的,这曾经是有效的,但现在已经不是这样了。

这些线路:

return oldItemsQuery.once('value', function(snapshot) {
/* ... use snapshot ... */
});

应该是:

return oldItemsQuery.once('value')
.then((snapshot) => {
/* ... use snapshot ... */
});

或:

const snapshot = await oldItemsQuery.once('value');
/* ... use snapshot ... */

接下来,您已经将onWrite侦听器配置为侦听/nodeThatContainsDataToBeDeleted上的更改。虽然这是有效的,但效率非常低。在/nodeThatContainsDataToBeDeleted(如/nodeThatContainsDataToBeDeleted/somePushId/someBoolean = true(下的某个时刻,对于数据库中的每一个小更改,函数都会下载该节点下嵌套的所有数据。对于这个节点上的几个条目,这是无关紧要的,但当您接近数千个条目时,您可能会读取许多兆字节的数据。

如果查看您链接的示例,侦听器将附加到/path/to/items/{pushId}(单个写入条目(,而不是/path/to/items(所有条目(。{pushId}过去是一个命名的通配符,它捕获路径的最后一部分(如-r5tyfX9FGC0glhgf78Ia(。

此行:

functions.database.ref('/nodeThatContainsDataToBeDeleted') // fetches all entries

应该是:

functions.database.ref('/nodeThatContainsDataToBeDeleted/{pushId}') // fetches only the entry that changed

注意:一个"bug";这个函数的作用是重新触发自己。对于它删除的每个条目,deleteOldItems将再次被激发。您可能希望使用.onCreate().onUpdate()而不是.onWrite()-有关更多信息,请参阅文档。

结合这些变化给出(基于撰写本文时的最新示例代码(:

// Copyright 2017 Google Inc., Apache 2.0
// Sourced at https://github.com/firebase/functions-samples/blob/master/delete-old-child-nodes/functions/index.js
// Cut off time. Child nodes older than this will be deleted.
const CUT_OFF_TIME = 2 * 60 * 60 * 1000; // 2 Hours in milliseconds.
/**
* This database triggered function will check for child nodes that are older than the
* cut-off time. Each child needs to have a `timestamp` attribute.
*/
exports.deleteOldItems = functions.database.ref('/nodeThatContainsDataToBeDeleted/{pushId}').onWrite(async (change) => {
const ref = change.after.ref.parent; // reference to the parent
const now = Date.now();
const cutoff = now - CUT_OFF_TIME;
const oldItemsQuery = ref.orderByChild('timestamp').endAt(cutoff);
const snapshot = await oldItemsQuery.once('value');
// create a map with all children that need to be removed
const updates = {};
snapshot.forEach(child => {
updates[child.key] = null;
});
// execute all updates in one go and return the result to end the function
return ref.update(updates);
});

相关内容

  • 没有找到相关文章

最新更新