如何使用Firebase将初始数据加载与增量子级分离?

如何使用Firebase将初始数据加载与增量子级分离?,firebase,firebase-realtime-database,Firebase,Firebase Realtime Database,我有一个应用程序,每5秒左右就会有新的孩子加入Firebase。我有成千上万的孩子 在应用程序加载时,我希望以不同的方式处理最初的数千个,而不是每5秒处理一次的后续子对象 你可能会建议我使用价值观,处理一切,然后使用孩子们。但我相信,如果处理时间太长,我可能会错过一个要点 在Firebase中有没有一种方法可以保证我不会漏掉任何一点?有两种可能的解决方案来解决这个问题,但都不能令人满意: 1) 为您的孩子添加时间戳,并且只请求时间戳大于“now”值的孩子。这不是很好,因为在将数据推送到Fireb

我有一个应用程序,每5秒左右就会有新的孩子加入Firebase。我有成千上万的孩子

在应用程序加载时,我希望以不同的方式处理最初的数千个,而不是每5秒处理一次的后续子对象

你可能会建议我使用价值观,处理一切,然后使用孩子们。但我相信,如果处理时间太长,我可能会错过一个要点


在Firebase中有没有一种方法可以保证我不会漏掉任何一点?

有两种可能的解决方案来解决这个问题,但都不能令人满意:

1) 为您的孩子添加时间戳,并且只请求时间戳大于“now”值的孩子。这不是很好,因为在将数据推送到Firebase或Firebase服务器的“now”值上,应用程序的“now”和“now”之间可能存在同步性问题

2) 使用增值和子增值。在添加的child_中看到的、在value中已经看到的任何重复项都可能被丢弃。这对于大型数据集是不适用的,因为它需要下载所有历史数据两次


为什么不能有一个像“child_added”这样的命令,它不能提供所有信息呢?

由于初始的、预加载的数据的
child_added
事件将在父对象上触发
value
事件之前触发,因此可以使用
value
事件作为一种“初始数据加载”通知。下面是一些我稍微修改过的代码

var initialdataload=false;
var ref=新的Firebase('https://.firebaseio.com');
参考on(“添加子项”),功能(快照){
如果(initialDataLoaded){
var msg=snapshot.val().msg;
//在这里做点什么
}否则{
//我们忽略此子项,因为它是预先存在的数据
}
});
参考一次(“值”,功能(快照){
initialDataLoaded=true;
});
谢天谢地,Firebase将智能地缓存这些数据,这意味着创建一个
child\u added
和一个
value
侦听器只需下载一次数据。为已经过线的数据添加新的Firebase侦听器是非常便宜的,而且您应该会觉得定期这样做很舒服


如果您担心在不需要的时候下载所有初始数据,我会按照@FrankvanPuffelen在评论中的建议使用时间戳查询。这非常有效,并且使用Firebase查询进行了优化。

改进了@jacobawenger的答案,使其不使用全局状态变量

var ref = new Firebase('https://<your-Firebase>.firebaseio.com');

ref.once('value', function(snapshot) {
  // do something here with initial value

  ref.on('child_added', function(snapshot) {
    // do something here with added childs
  });

});
var ref=new Firebase('https://.firebaseio.com');
参考一次(“值”,功能(快照){
//在这里用初始值做一些事情
参考on(“添加子项”),功能(快照){
//在这里做些事情,增加孩子
});
});

在数据库中添加了一个createdAt时间戳,并用当前时间限制了添加的子项,对我来说效果很好

const onChildAdded = database()
  .ref(refURL)
  .limitToLast(constValues.LAST_MESSAGE_ADDED)
  .orderByChild('createdAt')
  .startAt(date.getTime())
  .on('child_added', (snapshot) => {
    parseMessage(snapshot);
  });

database()
  .ref(refURL)
  .limitToLast(constValues.LAST_MESSAGES_LIMIT)
  .once('value', (snapshot) => {
    parseInitialMessages(snapshot);
    setLoading(false);
  });

如果使用
Firebase.ServerValue.timestamp
向子级添加时间戳,则使用
startAt
时,这将是微不足道的。你已经试过什么了吗?如果是的话,你能分享代码和它失败的地方(你担心)吗?可能的重复请参见:@FrankvanPuffelen如何管理Firebase服务器的时间戳和请求数据的任何东西之间的时间戳差异?请参见加藤发布的第一个链接。请不要将此作为答案发布,除非你认为这是一个答案。加藤给出了两个类似问题的链接。如果给出的答案对你不起作用,请编辑你的问题(下面有一个方便的编辑链接),包括一个最小的代码示例,显示你做了什么,并描述出问题所在。我总结了我从加藤给出的两个链接中得到的收获,并将其作为答案发布。另外:一个与之相关的解决方案有一个我正试图避免的问题:大型数据集的数据丢失。我会把这个问题贴在那个帖子里()事实上,我不允许评论,因为我的业力低于50。撇开必须下载两次数据的问题不谈,问题在于,对于大型数据集,child_添加完成与值完成之间存在时间间隔。由于添加的子项仅在值完成后处理,因此您可能会丢失数据。如果“解决方案”不是您的解决方案,则不要将其作为答案发布。您始终有权使用其他信息更新/编辑您的问题。我的问题已充分说明,无需进一步解释。我已经总结了其他人为这个问题提供的解决方案,并解释了为什么它们并不完美。如果有“更好”的解决方案,欢迎任何人提供,我会指出它是正确的。这是一个很好的答案。我不知道智能缓存,也没有看到其他地方提到过。谢谢你,雅各布。我确实有两个问题:如果值回调没有立即发生,或者回调本身需要很长时间才能执行(由于数据处理或其他原因),会发生什么?是否有可能在这段时间内添加一个孩子?Firebase应该保证在任何新添加的
child\u
事件触发之前触发
value
事件,因此您在那里应该没事。至于回调的数据处理,只要您立即检查
initialDataLoaded
变量,这就不重要了。如果您稍后在一堆阻塞代码之后在回调中检查它,它可能已切换到
true
,这就是我认为您的意思。您应该遵循通常的JavaScript最佳实践,因为这并不是一个真正针对Firebase的问题。@jacobawenger我一直在读到Firebase没有一种方法来获取初始数据,然后只获取更改的内容,这是“设计”造成的?这是因为按照设计,3路数据绑定假定已经管理了实时同步吗?我只是担心我正在尝试同步东西
const onChildAdded = database()
  .ref(refURL)
  .limitToLast(constValues.LAST_MESSAGE_ADDED)
  .orderByChild('createdAt')
  .startAt(date.getTime())
  .on('child_added', (snapshot) => {
    parseMessage(snapshot);
  });

database()
  .ref(refURL)
  .limitToLast(constValues.LAST_MESSAGES_LIMIT)
  .once('value', (snapshot) => {
    parseInitialMessages(snapshot);
    setLoading(false);
  });