0
votes

I would like to retrieve all children within a certain collection except one specific child. I have the database "users" which consists of multiple user id's.

"users"
|- "userId1"
|- "userId2"
|- "userId3"

and so on. I now want to retrieve only "userId1" and "userId3" and exclude "userId2". I already know, how to get just the userId2, because I have also stored it in another database, "blocked-users". This database consists of userIds as well as is build like this:

"blocked-users"
|- "userId1" 
      |- "userId2"

And that is the reason why I want to exclude userId2 from retrieving the users. Say userId1 is the currentUser and has blocked userId2, I want to prevent userId1 from finding userId2. How can I do this?

This is how I am getting the id of userId2:

guard let currentUid = Auth.auth().currentUser?.uid else { return }

BLOCKED_USERS.child(currentUid).observe(.childAdded) { (snapshot) in
                
    print("this is the user, that should not be shown: ", snapshot.key)

How can I now exclude the snapshot.key from being fetched within this function?:

var userCurrentKey: String?
USER_REF.queryLimited(toLast: 10).observeSingleEvent(of: .value) { (snapshot) in
                    
                    guard let first = snapshot.children.allObjects.first as? DataSnapshot else { return }
                    guard let allObjects = snapshot.children.allObjects as? [DataSnapshot] else { return }
                    
                    allObjects.forEach({ (snapshot) in
                        let uid = snapshot.key
                        
                        Database.fetchUser(with: uid, completion: { (user) in
                            self.users.append(user)
                            self.tableView.reloadData()
                        })
                    })
                    self.userCurrentKey = first.key
                }

This right here would be the entire function I call for fetching all the users:

func fetchUsers() {
        
        guard let currentUid = Auth.auth().currentUser?.uid else { return }
        
        if userCurrentKey == nil {
            
            BLOCKED_USERS.child(currentUid).observe(.childAdded) { (snapshot) in
                print("these are the users that have blocked this user: ", snapshot.key)
                
                var dontShowThisUser = snapshot.key
                
                USER_REF.queryLimited(toLast: 10).observeSingleEvent(of: .value) { (snapshot) in
                    
                    guard let first = snapshot.children.allObjects.first as? DataSnapshot else { return }
                    guard let allObjects = snapshot.children.allObjects as? [DataSnapshot] else { return }
                    
                    allObjects.forEach({ (snapshot) in
                        let uid = snapshot.key
                        
                        Database.fetchUser(with: uid, completion: { (user) in
                            self.users.append(user)
                            self.tableView.reloadData()
                        })
                    })
                    self.userCurrentKey = first.key
                }
            }
        } else {
            USER_REF.queryOrderedByKey().queryEnding(atValue: userCurrentKey).queryLimited(toLast: 5).observeSingleEvent(of: .value, with: { (snapshot) in
                
                guard let first = snapshot.children.allObjects.first as? DataSnapshot else { return }
                guard var allObjects = snapshot.children.allObjects as? [DataSnapshot] else { return }
                allObjects.removeAll(where: { $0.key == self.userCurrentKey })
                
                allObjects.forEach({ (snapshot) in
                    let uid = snapshot.key

                    if uid != self.userCurrentKey {
                        Database.fetchUser(with: uid, completion: { (user) in
                            self.users.append(user)
                            if self.users.count == allObjects.count  {
                                self.tableView.reloadData()
                            }
                        })
                    }
                })
                self.userCurrentKey = first.key
            })
        }
    }
1

1 Answers

0
votes

In general there is no way to exclude one (or some) nodes from a query. You will either have to load the entire users node and filter out the users you don't want in your application code, or you'll have to load the users you do want one by one.

The only variation on this is if you can use a query to slice the child nodes that you want and don't want. For example, if you have 99 users (user01 to user99 for simplicity) and won't read all but one user (say user42), you could do that with two queries:

usersRef.queryOrderedByKey().queryEnding(beforeValue: "user42")

and

usersRef.queryOrderedByKey().queryStarting(afterValue: "user42")

I don't think there's a gain by using this approach here though, as this is likely to be (slightly) less efficient and be more code to handle the two queries, than it'd be to filter the one node in the application code.