【问题标题】:Firebase Realtime database - only subscribe to single adds, updates, deletesFirebase 实时数据库 - 仅订阅单个添加、更新、删除
【发布时间】:2020-07-18 10:38:55
【问题描述】:

我在 Firebase 实时数据库中有一组项目。客户端订阅数据库的/items 路径中的修改。但这具有每次添加、更新或删除单个项目时将所有项目发送到客户端的效果。这可能是多达 1000 个项目被发送到客户端,因为项目文本已被更新为只有 一个 字符。

此代码有效,但不符合我的要求:

export const startSubscribeItems = () => {
  return (dispatch, getState) => {
    return new Promise(resolve => {
      database.ref('items')
      .orderByChild(`members/${uid}`)
      .equalTo(true)
      .on('value', (snapshot) => {
        let items = []
        snapshot.forEach( (childSnap) => {
          const id = childSnap.key
          const item = {id, ...childSnap.val()}
          items.push(item)
        })
        dispatch(setItems(items))
        resolve()
      })
    })
  }
}

我希望通过仅发送已更新的项目来提高网络成本效益 - 同时保持客户订阅。

我最初的想法是为每个项目实现订阅:

export const startSubscribeSingleItems = () => {
  return (dispatch, getState) => {
    return new Promise(resolve => {
      database.ref('items')
      .orderByChild(`access/members/${uid}`)
      .equalTo(true)
      .once('value', (snapshot) => {
        let items = []
        snapshot.forEach( (childSnap) => {
          const id = childSnap.key
          const item = {id, ...childSnap.val()}
          items.push(item)
          // .:: Subscribe to single item node ::.
          database.ref(`items/${id}`).on('value', (snap)=>{
             // Some logic here to handle updates and deletes (remove subscription)
          })
        })
        dispatch(setItems(items))
        resolve()
      })
    })
  }
}

这似乎有点麻烦,而且只处理更新和删除。它不处理其他客户添加的情况。添加必须通过单独的数据库节点(例如'subscriptionAdditions//')进行?此外 - 初始加载必须清除“subscriptionAdditions//”中的所有项目,因为第一次加载会读取所有项目。

再次,麻烦。 :/

总之;是否有一种简单和/或推荐的方法来实现在考虑多个客户的同时订阅单个项目?

亲切的问候 /K

【问题讨论】:

    标签: javascript node.js firebase-realtime-database subscription


    【解决方案1】:

    Firebase 实时数据库在服务器上的 JSON 结构和观察该状态的客户端之间同步状态。

    据我所知,您似乎只想同步该状态的一部分,主要是关于该状态的最新更改。在这种情况下,请考虑在数据库中对状态更改本身进行建模。

    随着您更多地使用 NoSQL 数据库,您会发现修改数据模型以允许每个用例是很常见的。


    例如,如果您只需要已更改节点的当前状态,则可以为每个节点添加lastUpdated 时间戳属性。然后你可以只查询更新节点:

    database.ref('items')
      .orderByChild('lastUpdated')
      .startAt(Date.now())
    

    如果您想监听自客户端上次联机以来的更改,您需要将它们上次联机的时间戳存储在某处,并使用它而不是 Date.now()


    如果您想同步所有状态更改,即使同一个节点被多次更改,您也需要将每个状态更改存储在数据库中。通过使用按时间顺序排列的键(例如由push() 生成的键)或为每个键存储时间戳,您可以使用与以前相同的逻辑来仅读取客户端尚未处理的状态更改。


    另见:

    【讨论】:

    • 非常感谢弗兰克!这是非常有用的信息! :D 有一个问题,orderByChild('lastUpdated') 会与 .orderByChild(members/${uid}).equalTo(true) 一起使用吗? /K
    • 没有。您一次只能对一个属性/键/值进行排序/过滤。有关更多和一些选项,请参阅stackoverflow.com/questions/26700924/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-04
    • 2018-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多