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.
}