Swift Firebase“;扇出;技术与有限效率

Swift Firebase“;扇出;技术与有限效率,swift,firebase,performance,firebase-realtime-database,Swift,Firebase,Performance,Firebase Realtime Database,我的应用程序中有一个群组聊天功能,其消息节点的结构如下。目前,它没有使用扇出技术。它只列出组名下的所有消息,例如“group1” 我首先观察了最近的40条信息,并观察了是否有新的孩子被添加进来 ref = Database.database().reference().child("groups").child("group1") ref.queryLimited(toLast: 40).observe(.childAdded, with: { (snap

我的应用程序中有一个群组聊天功能,其消息节点的结构如下。目前,它没有使用扇出技术。它只列出组名下的所有消息,例如“group1”

我首先观察了最近的40条信息,并观察了是否有新的孩子被添加进来

ref = Database.database().reference().child("groups").child("group1")
ref.queryLimited(toLast: 40).observe(.childAdded, with: { (snapshot) in
    ...
    //add to messages array to load collection view
    //for each message observe emojis and update emojis to reflect changes e.g. +1 like

    ref.child("emojis").observe(.value, with: { (snapshot) in
        ...
    })
})
每次用户向上滚动时,我都会使用最后一个日期(以及安全规则中的日期索引)加载另外40条消息(并观察每个消息节点下的emojis子节点)

我知道扇出技术用于每次同步获得的信息较少。如果我将侦听器附加到groups/groupname/以获取该组的所有消息的列表,我还将询问该节点下每条消息的所有信息。使用扇出的方法,我还可以通过使用来自另一个节点的消息的键来请求最近40条消息的消息信息,并向上滚动下40条消息

allGroups: {
    group1: {
      -MEt4K5xhsYL33anhXpP: 1
      -MEt8BLP2yMEUMPbG2zV: 1
      -MF-Grpl8Jchxpbn2mxH: 1
      -MF-OUjWXsFh7lBPosMf: 1
    }
}
然而,如果我使用queryLimited(toLast:40),扇出方法是有益的还是必要的?这难道不能解决“我还将询问该节点下每条消息的所有信息”的问题吗

在检查新消息方面,我只是在上面的第一个代码中使用.childAdded进行检查(ref.queryLimited(toLast:40).observe(.childAdded))。根据下面的帖子,queryLimited(toLast:40)将同步最后40个子节点,并保持同步(在添加新节点时删除以前的节点)

我假设group1有1000条消息,使用这种方法,我只需阅读我需要的40条最新消息,然后每卷阅读40条,从而忽略其他几百条消息。那么我为什么要使用扇出技术呢?可能是我不了解有限查询的一些基本内容


附带问题:我应该在每个消息节点下包含对概要文件图像的引用吗?在云存储和实时数据库存储方面这样做不好吗?理想情况下,会有数百次群聊。

对这个问题有很多评论,所以我想我会把所有这些浓缩成一个答案

问题中“扇出技术”的目的是最大化查询性能

在这个用例中,查询只返回最后40个结果

ref.queryLimited(toLast: 40)
问题中的假设是Firebase必须在40个节点之前“穿过”所有节点才能到达40个节点,因此会影响性能。Firebase的情况并非如此,因此无论是前40款还是后40款,性能都“相同”

因此,在这种情况下不需要“扇出”。为了清楚起见

扇出是复制数据库中数据的过程。什么时候 数据被复制—它消除了慢速连接并增加了读取 表演

我将从一个实例中窃取一个扇出示例。这里有一个扇出,可以一次更新多个节点,因为这是一个原子操作,它要么全部通过,要么全部失败

let updatedUser = ["name": "Shannon", "username": "shannonrules"]
let ref = Firebase(url: "https://<YOUR-FIREBASE-APP>.firebaseio.com")

let fanoutObject = ["/users/1": updatedUser, 
                    "/usersWhoAreCool/1": updatedUser, 
                    "/usersToGiveFreeStuffTo/1", updatedUser]

ref.updateChildValues(updatedUser) // atomic updating goodness

然后向表情节点添加一个观察者(更容易管理!)。当表情符号发生变化时,该观察者将通知应用程序该表情符号是用于哪条信息,以及变化是什么。它还将减少读取和总体成本。

分散数据可以采取多种形式。当你说“扇出技术”时,你能编辑你的问题来显示你心目中的JSON吗?当然。我不确定我是否理解这个新的数据结构与您问题顶部的数据结构之间的关系。如果您随后以查询无法处理的方式加载特定组(而不是其他组)的数据,那么最好有这样一个组ID列表。由于查询对您有效,我不会立即看到对分解数据的需要,但这可能是因为我现在不知道您的所有用例。数千个来自哪里?如果有数千个帖子,那么这些帖子中就有数千个表情符号的观察者。如果表情节点是独立的,那么相同的任务需要一个观察者,加载的数据更少;所以这只是一种设计选择。在用户节点中存储对图像的引用需要额外的读取,因为post被读取,然后用户节点从存储中获取pic。另一方面,在文章中保留ref可以减少阅读量,但是如果pic发生变化,你必须在每篇文章中更新它。我会投票支持上一个。
ref.queryLimited(toLast:40)
在你绞尽脑汁之前有点不清楚。这实际上是说‘无论查询是什么,限制在最后40个’;并不是为了得到最后的40分而质疑一切。因此,如果40是“在顶端”或40是“在末端”,那么性能是“相同的”;它不是“查看”其他顶部节点。读取性能不会受到显著影响,并且。。。Firebase速度极快,因此实际上很难制作出影响读取性能的东西@FrankvanPuffelen可能想纠正/更新我的观点,但我们的测试显示了这一点。
ref.queryLimited(toLast: 40)
let updatedUser = ["name": "Shannon", "username": "shannonrules"]
let ref = Firebase(url: "https://<YOUR-FIREBASE-APP>.firebaseio.com")

let fanoutObject = ["/users/1": updatedUser, 
                    "/usersWhoAreCool/1": updatedUser, 
                    "/usersToGiveFreeStuffTo/1", updatedUser]

ref.updateChildValues(updatedUser) // atomic updating goodness
emojis
   -MEt4K5xhsYL33anhXpP: //the message id
      "heart": 2  //or however you want to store them
      "like": 1