【问题标题】:Node: Check a Firebase db and execute a function when an objects time matches the current time节点:检查 Firebase 数据库并在对象时间与当前时间匹配时执行函数
【发布时间】:2018-02-09 09:08:24
【问题描述】:

背景

我有一个基于 Node 和 React 的应用程序。我正在使用 Firebase 作为我的存储和数据库。在我的应用程序中,用户可以填写一张表格,在其中上传图片并选择将图片添加到他们网站的时间。我像这样将每个图像更新保存为我的 Firebase 数据库中的一个对象。图片按更新时间升序排列。

user-name: {
   images: [
     {
        src: 'image-src-url',
        updateTime: 1503953587727
     }
     {
        src: 'image-src-url',
        updateTime: 1503958424838
     }
   ]
}

缩放

我的应用程序数据库可能会因大量用户和图像而变得非常大。我想确保可扩展性。

问题

如何检查何时满足特定图像对象时间然后执行功能? (我不需要关于正在运行的实际功能的帮助,只是在特定时间检查数据库。)

尝试

我考虑过使用node-cron 执行一项 cron 作业,它每 60 秒检查一次整个数据库(用户只能指定图像更新的分钟数,而不是秒数。)然后,如果它找到匹配的 updateTime 并执行我的功能。我主要担心 cron 作业需要一段时间来搜索数据库,并且可能会错过时间。

我还考虑过用户何时安排新的更新,然后为该时间动态创建特定的 cron 作业。我不确定如何做到这一点。

还有其他可行的方法吗?我对 node-cron 的担忧是否无效?

【问题讨论】:

    标签: node.js firebase firebase-realtime-database cron


    【解决方案1】:

    我能想到两种方法:

    1. 跟踪您处理的最后一个时间戳
    2. 将“要处理的事情”放在队列中

    跟踪您处理的最后一个时间戳

    在处理项目时,您使用当前时间戳作为查询的截止点。比如:

    var now = Date.now();
    var query = ref.orderByChild("updateTime").endAt(now)
    

    现在确保将此now 存储在某处(即在您的数据库中),以便您下次可以重新使用它来检索下一批项目:

    var previous = ... previous value of now
    var now = Date.now();
    var query = ref.orderByChild("updateTime").startAt(previous).endAt(now);
    

    这样,您一次只能处理一个切片。唯一棘手的一点是,有人可能会插入一个带有您已经处理过的updateTime 的新节点。如果这是您的用例所关心的问题,您可以使用updateTime 上的验证规则阻止他们这样做:

    ".validate": "newData.val() >= root.child('lastProcessed').val()"
    

    当您向数据库添加更多项目时,您确实会查询更多项目。所以这种方法有一个可扩展性限制,但是这种方法应该适用于多达几十万个节点的任何东西(我有一段时间没有测试过,所以 ymmv)。

    对于之前关于列表大小的几个问题:

    将“要处理的事情”放在队列中

    另一种方法是保留仍需要处理的项目队列。因此,客户端将他们想要处理的项目添加到队列中,并带有他们想要处理的时间的updateTime。然后您的服务器从队列中挑选项目,执行必要的更新,然后从队列中删除项目

    var now = Date.now();
    var query = ref.orderByChild("updateTime").endAt(now)
    query.once("value").then(function(snapshot) {
      snapshot.forEach(function(child) {
    
        // TODO: process the child node
    
        // remove the child node from the queue
        child.ref.remove();
      });
    })
    

    与早期方法的不同之处在于,队列的稳定状态将为空(或至少非常小),因此您的查询将针对更小的列表运行。这也是为什么您不需要跟踪您处理的最后一个时间戳的原因:到目前为止,队列中的任何项目都符合处理条件。

    【讨论】:

    • 在这里坦白伟大的想法。我倾向于第二种选择。您认为队列应该与我的常规数据库列表分开吗? IE 目前我确实有一个“队列”,但它存储在每个个人用户 ID 下。您是否建议我还将图像添加到名为“队列”的新节点?或者我可以保留我的结构并执行您建议的相同查询吗?
    • 选项 2 确实是队列的一个单独节点,您在处理完项目后将其删除,
    • 选项 #2 是我要使用的选项!它使我的数据库写入更复杂,但有助于这些快速读取。
    • Frank - 鉴于我是一个新应用程序并且尚未启动,我正在考虑将我的数据库迁移到 Cloud Firestore。该决定的一个重要因素是快速查询和处理已满足更新时间的图像的能力。鉴于我几个月前的问题,您是否建议我进行迁移?您的方法 #2 是否会转化为为队列单独收集?
    • 虽然 Cloud Firestore 提供了更好的可扩展性并显着简化了对多个属性的查询,但我认为它在这种情况下并没有提供任何明显不同的东西。您确实会为队列创建一个单独的集合。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-17
    • 1970-01-01
    • 1970-01-01
    • 2013-01-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多