Node.js 使用Firebase云函数删除旧数据

Node.js 使用Firebase云函数删除旧数据,node.js,firebase,firebase-realtime-database,google-cloud-functions,Node.js,Firebase,Firebase Realtime Database,Google Cloud Functions,我需要定期从Firebase中删除旧数据。我找到了,但没能使它工作 终端告诉我功能[deleteOldItems(us-central1)]:更新操作成功。但数据未被删除 这就是我所做的: const functions = require('firebase-functions'); exports.deleteOldItems = functions.database.ref('/nodeThatContainsDataToBeDeleted') .onWrite((change, con

我需要定期从Firebase中删除旧数据。我找到了,但没能使它工作

终端告诉我
功能[deleteOldItems(us-central1)]:更新操作成功。
但数据未被删除

这就是我所做的:

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);
  });
});
时间戳是
639915248.124176
(来自Swift)

数据库结构:

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

当您在后台触发的云函数中执行异步操作时(在您的例子中是
once()
update()
方法),您必须返回一个承诺,以这种方式,云函数将等待此承诺解析以终止。标题为“学习JavaScript承诺”的三篇文章中有更多的信息(第2部分和第3部分特别关注后台触发的云函数,但之前的第1部分确实值得一看)

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

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

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);
            });
    });
这个答案建立在他的基础上

JavaScript和Firebase SDK自2015年以来已经取得了长足的进步,因此在复制/使用StackOverflow上的旧代码示例时要小心这一点。网站还链接到最新的具有现代特色的网站

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

这些线路:

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

return oldItemsQuery.once('value')
  .then((snapshot) => {
    /* ... use snapshot ... */
  });
functions.database.ref('/nodeThatContainsDataToBeDeleted/{pushId}') // fetches only the entry that changed
或:

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

如果查看链接的示例,侦听器将附加到
/path/to/items/{pushId}
(单个书面条目),而不是
/path/to/items
(所有条目)。
{pushId}
过去是一个捕获路径最后一部分的过程(如
-r5tyfX9FGC0glhgf78Ia

这一行:

functions.database.ref('/nodeThatContainsDataToBeDeleted') // fetches all entries
应该是:

return oldItemsQuery.once('value')
  .then((snapshot) => {
    /* ... use snapshot ... */
  });
functions.database.ref('/nodeThatContainsDataToBeDeleted/{pushId}') // fetches only the entry that changed
注意:此函数的一个“错误”是它会重新触发自身。对于它删除的每个条目,
deleteOldItems
将再次触发。您可能希望使用
.onCreate()
.onUpdate()
而不是
.onWrite()
-有关详细信息,请参阅

结合这些变化(在撰写本文时建立):


该终端消息只是说明名为
deleteOldItems
的云函数已成功部署。它与您的代码无关。请在问题中包括您的数据库结构。@samthecodingman包括数据库结构
NodeThatContainesDataObeDeleted
直接位于根目录下,因此您所指的问题是:“每当在/path/to/items下写入数据时,就会触发此函数,因此只有在修改数据时才会删除子节点。”您是如何触发此函数的?