Firebase child_added 仅适用于新项目

Posted

技术标签:

【中文标题】Firebase child_added 仅适用于新项目【英文标题】:Firebase child_added for new items only 【发布时间】:2017-09-12 10:43:59 【问题描述】:

我将 Firebase 和 Node 与 Redux 一起使用。我正在从一个键加载所有对象,如下所示。

firebaseDb.child('invites').on('child_added', snapshot => 
)

这种方法背后的想法是,我们从数据库中获取有效负载,并且只使用一个操作通过 Reducer 更新我的本地数据存储。

接下来,我需要监听密钥邀请的任何 NEWUPDATED 子级。 然而,现在的问题是 child_added 事件会触发所有现有键以及新添加的键。我不想要这种行为,我只需要新密钥,因为我已经检索了现有数据。

我知道 child_added 通常用于这种类型的操作,但是,我希望减少触发的操作数量,并因此触发渲染。

实现这一目标的最佳模式是什么?

谢谢,

【问题讨论】:

只有当监听器第一次触发时,child_added 才会触发该节点子节点的数量,之后才会在添加新子节点时触发。 我知道,这就是我在问题中提到的......我只想要新项目...... 【参考方案1】:

虽然limit方法相当不错并且效率很高,但是你仍然需要在child_added中添加一个检查,最后一个要抓取的项目。另外我不知道是否仍然如此,但是您可能会从以前删除的项目中获得“旧”事件,因此您可能也需要注意这一点。

其他解决方案是:

使用布尔值防止旧添加的对象调用回调

let newItems = false

firebaseDb.child('invites').on('child_added', snapshot => 
  if (!newItems)  return 
  // do
)

firebaseDb.child('invites').once('value', () => 
  newItems = true
)

这种方法的缺点是它意味着如果你有一个很大的初始列表,它可能会导致什么都不做的事件可能会出现问题。

或者,如果您的邀请上有时间戳,请执行以下操作

firebaseDb.child('invites')
  .orderByChild('timestamp')
  .startAt(Date.now())
  .on('child_added', snapshot => 
  // do
)

【讨论】:

在使用时间戳时不要忘记考虑服务器和客户端之间的时间差。查看文档中的Clock skew。检索到 serverTimeOffset 后,可以轻松添加它,例如 .startAt(Date.now() + serverTimeOffset)【参考方案2】:

我已经使用以下方法解决了这个问题。

firebaseDb.child('invites').limitToLast(1).on('child_added', cb)
firebaseDb.child('invites').on('child_changed', cb)

limitToLast(1) 获取邀请的最后一个子对象,然后侦听任何新的子对象,将快照对象传递给 cb 回调。

child_changed 监听任何对邀请的子更新,将快照传递给 cb

【讨论】:

limitToLast(1) 承诺最后添加的项目正常。但是如果在您授权之前添加了超过 1 条记录会发生什么。除了最后一个,它会丢失它们。我认为错误的答案。对吗? 这对我不起作用。添加的孩子不会触发任何事件。【参考方案3】:

我通过忽略child_added 并仅使用child_changed 解决了这个问题。我这样做的方法是对我需要处理的任何项目执行update()将它们推送到数据库之后。此解决方案将取决于您的需求,但一个示例是在您希望触发事件时更新时间戳键。例如:

var newObj =  ... 
// push the new item with no events
fb.push(newObj)
// update a timestamp key on the item to trigger child_changed
fb.update( updated: yourTimeStamp )

【讨论】:

【参考方案4】:

还有另一种解决方案: 获取孩子的数量并提取该值: 它正在工作。

var ref = firebaseDb.child('invites')
ref.once('value').then((dataSnapshot) => 
        return dataSnapshot.numChildren()
    ).then((count) =>
        ref .on('child_added', (child) => 
            if(count>0)
                count--
                return
            
            console.log("child really added")
          );
     );

【讨论】:

【参考方案5】:

如果您的文档键是基于时间的(unix epoch、ISO8601 或 firebase 'push' 键),这种方法类似于 @balthazar 提出的第二种方法,对我们来说效果很好:

const maxDataPoints = 100; 
const ref = firebase.database().ref("someKey").orderByKey();
// load the initial data, up to whatever max rows we want
const initialData = await ref.limitToLast(maxDataPoints).once("value")
// get the last key of the data we retrieved
const lastDataPoint = initialDataTimebasedKeys.length > 0 ? initialDataTimebasedKeys[initialDataTimebasedKeys.length - 1].toString() : "0"
// start listening for additions past this point...
// this works because we're fetching ordered by key
// and the key is timebased
const subscriptionRef = ref.startAt(lastDataPoint + "0");
const listener = subscriptionRef.on("child_added", async (snapshot) => 
    // do something here
);

【讨论】:

以上是关于Firebase child_added 仅适用于新项目的主要内容,如果未能解决你的问题,请参考以下文章

Firebase Api Key 仅适用于 iOS

Firebase 云消息传递仅适用于本地主机

Firebase 动态链接仅适用于模拟器 |扑

firebase 社交登录不适用于我的 android 设备,仅适用于网络

如何将 Firebase 数据检索到 TableView android 中?我应该使用 RecycleView 还是仅适用于列表?

android面临崩溃报告仅适用于8.0和8.1中的firebase通知