Firebase Swift 查询和客户端扇出
Firebase Swift query and client side fan out
我已经处理这个问题三天多了,我进行了研究并遇到了与我的问题相关的其他类似问题,但这些修复无法解决我的问题,因此我提出这个问题的原因。
我在 firebase 中有一个 users、posts 和 users-posts 节点,如下所示。我想 运行 在节点上进行查询,这样如果两个用户是朋友,他们就可以看到对方 post。但如果他们不是朋友,他们就看不到对方 posts
Users
123840ajldkjfas0d9
username: Joe
friend
78983049802930laks: true
78983049802930laks: true
4563049802930laks
username: Ken
friend
123840ajldkjfas0d9: true
78983049802930laks
username: Pean
friend
123840ajldkjfas0d9: true
posts
876f92fh02hfj02930239
post: This is cool
whoposted: 123840ajldkjfas0d9
39fh938hqw9320923308
post: I love pizza
whoposted: 78983049802930laks
users-posts
123840ajldkjfas0d9
876f92fh02hfj02930239: true
78983049802930laks
39fh938hqw9320923308: true
这是我目前的查询,它显示了所有用户的所有 post,无论他们是否是朋友。我需要帮助。
DataService.ds.REF_USERS.observe(.value, with: { (userSnapshot) in
if let snapshot = userSnapshot.children.allObjects as?
[FIRDataSnapshot]{
for userSnap in snapshot{
print("snapshot.key: \(userSnap.key)")
let userKey = userSnap.key
if var userDict = userSnap.value as? Dictionary<String,
AnyObject>{
let postUserPicUrl = userDict["profileImgUrl"] as? String
if let firstName = userDict["firstName"] as? String{
("firstName: \(firstName)")
DataService.ds.REF_POST.observeSingleEvent(of: .value, with: {
(postSnapshot) in
if let postSnapshot = postSnapshot.children.allObjects as?
[FIRDataSnapshot]{
for postSnap in postSnapshot{
if var postDict = postSnap.value as? Dictionary<String, AnyObject>{
if let refPostUserKey = postDict["user"] as? String{
if userKey == refPostUserKey{
DataService.ds.REF_BLOCK_USER.observeSingleEvent(of: .value, with: {
(blockUserSnapshot) in
if let blockUserSnapshot = blockUserSnapshot.children.allObjects as?
[FIRDataSnapshot] {
for blockUserSnap in blockUserSnapshot{
if var blockUserDict = blockUserSnap.value as? Dictionary<String,
AnyObject> {
if let user = blockUserDict["user"] as? String{
if firstName != user {
postDict["postUserPicUrl"] = postUserPicUrl as AnyObject?;
let postKey = postSnap.key
let post = Post(postKey: postKey, postData: postDict)
self.posts.append(post)
}
}
}
}
}
self.tableView.reloadData()
})
}
}
}
}
}
self.tableView.reloadData()
})
}
}
}
}
self.tableView.reloadData()
})
}
我的意思是没有任何不尊重,但您没有很好地利用这些查询,每个查询都嵌套在另一个查询中。另外,请确保更新所有查询。 Post 查询使用旧格式,而您的用户查询是最新的。
您应该创建 3 个字典来保存每个节点用户的数据,posts,users-posts 以及一个 var 来保存当前用户字符串和一个字典来包含 post数据:
var users = [String:Any]()
var posts = [String:Any]()
var usersposts = [String:Any]()
var currentUserKey:String!
var visibleposts = [String:Any]()
然后有三个单独的查询来获取数据。目前您似乎没有查询任何特定用户,所以我也会这样做:
func getUserData(){
DataService.ds.REF_USERS.observe(.childAdded, with: {snapshot in
let key = snapshot.key
let data = snapshot.value as? [String:Any] ?? [:]
self.users[key] = data
})
}
func getPostsData(){
DataService.ds.REF_POST.observe(.childAdded, with: {snapshot in
let key = snapshot.key
let data = snapshot.value as? [String:Any] ?? [:]
self.posts[key] = data
self.refreshPosts()
})
}
func getUsersPostsData(){
DataService.ds.REF_BLOCK_USERS.observe(.childAdded, with:{snapshot in // I am guessing you have the users posts here?? there doesn't seem to be sample data for blocked users in your OP
let key = snapshot.key
let data = snapshot.value as? [String:Any] ?? [:]
self.usersposts[key] = data
self.refreshPosts()
})
}
现在在加载视图中触发这些查询之前获取当前用户,然后调用每个查询。
override func viewDidLoad(){
self.currentUserKey = (FIRAuth.auth()?.currentUser?.uid)!
/* you may want to do some error handling here to ensure the user
is actually signed in, for now this will get the key if
they are signed in */
self.getUserData()
self.getPostsData()
self.getUsersPostsData()
// data will be refreshed anytime a child is added
}
func refreshPosts(){
self.validposts = [:]
let validUsers = [String]() // this will hold the valid keys to get posts
validUsers.append(self.currentUserKey)
let currentUserData = users[self.currentUserKey] // filter the current user data to get the friends
// get friends keys
let friendsData = currentUserData["friends"] as? [String:Any] ?? [:]
for key in friendsData.keys {
// add friends posts to the validposts data
validUsers.append(key)
}
// get current users posts:
for (key,value) in self.posts {
let postData = value as? [String:Any] ?? [:]
let whoposted = postData["whoposted"] as? String ?? ""
if validUsers.contains(whoposted){
self.validposts[key] = postData
}
}
// access the self.validposts data in your UI however you have it setup
// The child added queries above will continue to fire off and refresh
// your data when new posts are added.
// I am still not clear what the usersposts data is for so it is omitted here.
}
我已经处理这个问题三天多了,我进行了研究并遇到了与我的问题相关的其他类似问题,但这些修复无法解决我的问题,因此我提出这个问题的原因。
我在 firebase 中有一个 users、posts 和 users-posts 节点,如下所示。我想 运行 在节点上进行查询,这样如果两个用户是朋友,他们就可以看到对方 post。但如果他们不是朋友,他们就看不到对方 posts
Users
123840ajldkjfas0d9
username: Joe
friend
78983049802930laks: true
78983049802930laks: true
4563049802930laks
username: Ken
friend
123840ajldkjfas0d9: true
78983049802930laks
username: Pean
friend
123840ajldkjfas0d9: true
posts
876f92fh02hfj02930239
post: This is cool
whoposted: 123840ajldkjfas0d9
39fh938hqw9320923308
post: I love pizza
whoposted: 78983049802930laks
users-posts
123840ajldkjfas0d9
876f92fh02hfj02930239: true
78983049802930laks
39fh938hqw9320923308: true
这是我目前的查询,它显示了所有用户的所有 post,无论他们是否是朋友。我需要帮助。
DataService.ds.REF_USERS.observe(.value, with: { (userSnapshot) in
if let snapshot = userSnapshot.children.allObjects as?
[FIRDataSnapshot]{
for userSnap in snapshot{
print("snapshot.key: \(userSnap.key)")
let userKey = userSnap.key
if var userDict = userSnap.value as? Dictionary<String,
AnyObject>{
let postUserPicUrl = userDict["profileImgUrl"] as? String
if let firstName = userDict["firstName"] as? String{
("firstName: \(firstName)")
DataService.ds.REF_POST.observeSingleEvent(of: .value, with: {
(postSnapshot) in
if let postSnapshot = postSnapshot.children.allObjects as?
[FIRDataSnapshot]{
for postSnap in postSnapshot{
if var postDict = postSnap.value as? Dictionary<String, AnyObject>{
if let refPostUserKey = postDict["user"] as? String{
if userKey == refPostUserKey{
DataService.ds.REF_BLOCK_USER.observeSingleEvent(of: .value, with: {
(blockUserSnapshot) in
if let blockUserSnapshot = blockUserSnapshot.children.allObjects as?
[FIRDataSnapshot] {
for blockUserSnap in blockUserSnapshot{
if var blockUserDict = blockUserSnap.value as? Dictionary<String,
AnyObject> {
if let user = blockUserDict["user"] as? String{
if firstName != user {
postDict["postUserPicUrl"] = postUserPicUrl as AnyObject?;
let postKey = postSnap.key
let post = Post(postKey: postKey, postData: postDict)
self.posts.append(post)
}
}
}
}
}
self.tableView.reloadData()
})
}
}
}
}
}
self.tableView.reloadData()
})
}
}
}
}
self.tableView.reloadData()
})
}
我的意思是没有任何不尊重,但您没有很好地利用这些查询,每个查询都嵌套在另一个查询中。另外,请确保更新所有查询。 Post 查询使用旧格式,而您的用户查询是最新的。
您应该创建 3 个字典来保存每个节点用户的数据,posts,users-posts 以及一个 var 来保存当前用户字符串和一个字典来包含 post数据:
var users = [String:Any]()
var posts = [String:Any]()
var usersposts = [String:Any]()
var currentUserKey:String!
var visibleposts = [String:Any]()
然后有三个单独的查询来获取数据。目前您似乎没有查询任何特定用户,所以我也会这样做:
func getUserData(){
DataService.ds.REF_USERS.observe(.childAdded, with: {snapshot in
let key = snapshot.key
let data = snapshot.value as? [String:Any] ?? [:]
self.users[key] = data
})
}
func getPostsData(){
DataService.ds.REF_POST.observe(.childAdded, with: {snapshot in
let key = snapshot.key
let data = snapshot.value as? [String:Any] ?? [:]
self.posts[key] = data
self.refreshPosts()
})
}
func getUsersPostsData(){
DataService.ds.REF_BLOCK_USERS.observe(.childAdded, with:{snapshot in // I am guessing you have the users posts here?? there doesn't seem to be sample data for blocked users in your OP
let key = snapshot.key
let data = snapshot.value as? [String:Any] ?? [:]
self.usersposts[key] = data
self.refreshPosts()
})
}
现在在加载视图中触发这些查询之前获取当前用户,然后调用每个查询。
override func viewDidLoad(){
self.currentUserKey = (FIRAuth.auth()?.currentUser?.uid)!
/* you may want to do some error handling here to ensure the user
is actually signed in, for now this will get the key if
they are signed in */
self.getUserData()
self.getPostsData()
self.getUsersPostsData()
// data will be refreshed anytime a child is added
}
func refreshPosts(){
self.validposts = [:]
let validUsers = [String]() // this will hold the valid keys to get posts
validUsers.append(self.currentUserKey)
let currentUserData = users[self.currentUserKey] // filter the current user data to get the friends
// get friends keys
let friendsData = currentUserData["friends"] as? [String:Any] ?? [:]
for key in friendsData.keys {
// add friends posts to the validposts data
validUsers.append(key)
}
// get current users posts:
for (key,value) in self.posts {
let postData = value as? [String:Any] ?? [:]
let whoposted = postData["whoposted"] as? String ?? ""
if validUsers.contains(whoposted){
self.validposts[key] = postData
}
}
// access the self.validposts data in your UI however you have it setup
// The child added queries above will continue to fire off and refresh
// your data when new posts are added.
// I am still not clear what the usersposts data is for so it is omitted here.
}