考虑以下数据库树:
root: {
followees: {
<uid-1> : {
// list of all users "uid-1" is following (each child node is a different FCM topic)
<uid-1-1>: true, // true = subscribed to FCM topic
<uid-1-2>: false,
// theoretically, "uid-1" could be following millions of users, but 100k is probably a more reasonable maximum
}
<uid-2> : {
// list of all users "uid-2" is following
}
}
}
在subtree
中迭代所有孩子的最有效和节省内存的方法是什么?
我使用限制查询创建了一个递归解决方案,一次读取1000个孩子。这是有效的,但是由于递归方面的原因,所有的子节点都存储在内存中,直到它遇到基本情况为止;它与一次装载所有孩子基本相同。
我已经考虑过清除observeSingleEvent(.value)
返回的集合,但这不起作用,因为集合是不可变的。
我能想到的最佳解决方案是查询数据库中前1000个孩子,然后查询第二个1000,依此类推:
query(startIndex:0, endIndex:999)
query(startIndex:1000, endIndex:1999)
query(startIndex:2000, endIndex:2999)
...
如何使用Firebase完成此操作?它可以完成吗?我的数据库结构是否应该重新设计,以便子树不能包含数百万个条目?
感谢任何建议!
P.S。如果您有兴趣,这是我的递归解决方案。请注意,它不是有效的Swift代码 - 它只是显示了这个概念。
func iterateChildren(startingAt: String, block: (child) -> Void) {
// The actual query would use queryStartingAt and queryLimited.
ref.query { children in
// Used in recursive call.
var nextStartingId: String? = nil
for (index, child) in children.enumerated() {
if (UInt(index) == limit - 1) {
// Firebase Database's queryStarting(atValue:) method is inclusive of
// atValue, so skip the last item as it will be included in the next
// iteration.
nextStartingId = child.key
break
}
block(child)
}
if (nextStartingId != nil) {
self.iterateChildren(startingAtId: nextStartingId, block: block)
}
}
}
答案 0 :(得分:1)
而不是单个大孩子,尝试使用小而简洁的孩子。你为什么不尝试用你的子逻辑分组?
一个不错的解决方案可能是按插入日期对数据进行分组(但取决于您的用例):
root : {
child : {
"20/09/2017" : {
"uid" : true
},
"21/09/2017" : {
"uid" : false
"uid" : true
}
}
}
使用此解决方案,您可以使用observe(.childAdded)
迭代子节点,其中每个completionHandler都会为您提供一小块数据。
无论如何,我确信使用.value
观察者是一个糟糕的解决方案。
Firebase建议避免使用神童,因此请尝试遵循以下简单规则:https://firebase.google.com/docs/database/ios/structure-data