Search Filtering
Instagram Firebase
In order to perform a fast and efficient search for the users in our Firebase Database, we'll first need to fetch all of our users with an observation. Once we build our list of users, we'll present it inside of our UserSearchController. Next, we'll examine the behavior of delegating our search bar behavior to detect when the search text is changed. Finally, we can perform a filtering of our users so that our list responds when searching.

Comments (23)
tyehowatt
6 years ago
hey one last question, im adding detail to the search so before yhe user types anything in it shows the most popular posts ordered by most likes. But it only shows the current users posts how would I go about get every users post? Thank you so much
Brian Voong
6 years ago
tyehowatt
6 years ago
I tried to do that but don't think I understand it fully could you show me how to do it ?
tyehowatt
6 years ago
I tried observing just the child of "Posts" but when we set post = Post(user: ? Dictonary: dictonary) what do i put for user?
tyehowatt
6 years ago
hey briain still waiting for your response.....
Brian Voong
6 years ago
Slava Nagornyak
6 years ago
Thank you for mention my tip about isEmpty and included it inside your course. I'm so glad :]
zcrystal
6 years ago
Hey Brian, Is your sort method the same as using " self.users.sort { $0.username < $1.username } " Just based on what I've learned from you, the lesser amount of code for the same result is an improvement, so just wondering if this achieves the same result!
Brian Voong
6 years ago
Razzor Owa
6 years ago
Hey, Brian... I'd like to know how to set the "Number of Posts" of each user in the Search View. I tried to do it using a observeSingleEvent inside another one (one of them to observe the users tree and the other to observe the posts tree) but I had problems with the async nature of those Firebase functions. Could you post the completed application code for us?
Antonio Di Francesco
6 years ago
Brian, I'd like to point out that the .lowercased() has to be used also in the sorting function. If not, the result would be: at first, the ordered upper case usernames first, then, the ordered lower case usernames, it seems like they are treated as two different "blocks". Thanks for the episode!
Dan Boyle
6 years ago
I noticed something strange. When I search for a user and then delete my search string, the users that did not have a profile image, now have a profile image, or at least one is rendering in the image view. Is anybody else noticing this?
Brian Voong
6 years ago
Heriberto Cantu
5 years ago
I noticed that "old pic" appear 1 second while scrolling in a slow network and then replaced by the real while re-utilizing the cell. In cellForItemAt I use to do for all images: cell.profileImageView.isHidden = true And in CustomImageView loadImage() anywhere you set the image if found or not: self.isHidden = false
yoowinks
5 years ago
I found similar behaviour in my code. Each time I typed a character in the search bar, the images would change. Using Heriberto's suggestion worked - thank you. Just want to add that within loadImage() the suggested line must be placed within the main queue like so: DispatchQueue.main.async { self.isHidden = false self.image = photoImage }
LucaKiedrowski
6 years ago
Hey Brian, love your videos! Love this course. I have found that for large user datasets, its very ineffictient to fetch them all and then filter the array. It's definitly enough for this course! For everyone that is interested in handling a bigger amount of Users: It would be nicer, if we could search "in the database" and then fetch every user, that fits our searchText. So, it would user this function instead of fetchUser(): func fetchUserWithUsername(searchText: String) { filteredUsers = [User]() let userRef = Database.database().reference().child("users").queryOrdered(byChild: "username").queryStarting(atValue: searchText).queryEnding(atValue: searchText+"\u{f8ff}") userRef.observeSingleEvent(of: .value, with: { (snapshot) in guard let dictionaries = snapshot.value as? [String: Any] else { return } dictionaries.forEach({ (key, value) in guard let userDictionary = value as? [String: Any] else { return } let user = User(uid: key, dictionary: userDictionary) let isContained = self.filteredUsers.contains(where: { (containedUser) -> Bool in return user.id == containedUser.id }) if !isContained { self.filteredUsers.append(user) self.collectionView?.reloadData() } }) }) { (err) in print("failed to fetch searched User", err) } } I use it in func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String), every time the text isn't empty. If the searchBar is empty, maybe it would be nice to fetch the first 10 user in the database, so you could use a different DatabaseReference: Database.database().reference().child("users").queryLimited(toFirst: 10) Maybe this will help some people :) Kindest Regards, Luca
LucaKiedrowski
6 years ago
One thing, that I have to mention: This only works for lowercased names in the Database. So you have two options: 1. You can include an additional variable in that JSON Object, something like "searchUsername", which is just the username in lowercased form. 2. You can make every username lowercased.
albaqawi
5 years ago
very nice input Luca I definitely love to get this in my code.... @Brain, can you provide a suggestion on how to search on dynamic user list to include users newly created since the current user logged in and wants to preform a search. goal i guess to ensure we capture all matches in DB
stevezhou
5 years ago
The downside of this is that your server cost will go up a lot.
omair_34
5 years ago
Very helpful Luca !
nikosm
5 years ago
Hi, I want to use the same way, to fetch users dynamically from firebase, depending on the searchText of the search bar...Brian can you tell us if it is worth it to use something like this or which is the best way to do that?
Sanket Ray
5 years ago
We can use this to sort as well : self.users.sort(by : { u1, u2 ) -> Bool in return u1.username < u2.username }) Is this approach not recommended?
Brian Voong
5 years ago
h01m3s
5 years ago
"<" operator doesn't handle case sensitivity correctly. I think one of the correct way to do this is self.users.sort { $0.username.caseInsensitiveCompare($1.username) == .orderedAscending }
Sanket Ray
5 years ago
Hey Brian, When searching for users, how can we highlight the text that matches with the results?
Brian Voong
5 years ago
Sanket Ray
5 years ago
Yes, I was able to solve it. Thanks anyways.
kvnpraveen
5 years ago
I am trying to do the same. I am stuck at passing the text entered in the search field to the UserSearchCell to calculate the range. Any help would be appreciated.
Kenny Ho
5 years ago
Hi guys, what's the reason why at 11:10, we have "guard let profileImageUrl =". How come we didn't have to do it for usernameLabel? Can someone explain to be the reasoning behind that? Thank you :)
Brian Voong
5 years ago
Kenny Ho
5 years ago
Very much appreciate your quick reply Brian! Thank you.
PreachOnBerto
5 years ago
Hey Brian, When scrolling down through the collection view everything all users are displaying profile images correctly, but when I scroll back up, I see that some of my users are displaying the wrong profile image. What could the issue be? Best, Roberto
johnsoa7
4 years ago
Hi Roberto, I have the same issue, did you manage to resolve this and if so, how? Thanks, Abraham
Aurélien Haie
5 years ago
Hello guys! Here we download the whole content of users to filter them after thanks to the searchBar, but that means we have to download a lot of users.. is it bad for the use of CPU or 4G/wifi data volume? What if there are 1 million of users in the database, the app downloads a DataSnapshot from Firebase with 1 million of entries? is it working really or does it make the app crash? I was wondering if we could use pagination with filtering feature.. Thanks
Brian Voong
5 years ago
cwoodall6
5 years ago
You could also look into doing it async dispatch so they just load as they come
benpalmer661
5 years ago
hi Brian when my page loads it doesn't load all the users on the screen until i enter something in the search bar then backspace it? I change your code slightly as i am using the new firebase firestore database here is my fetch user code , any ideas? fileprivate func fetchUsers() { guard let uid = Auth.auth().currentUser?.uid else { return } let db = Firestore.firestore() db.collection("Users").document(uid).collection("Contacts").getDocuments() { (querySnapshot, err) in if let err = err { print("Error getting documents: \(err)") } else { for document in querySnapshot!.documents { let d = document.data() d.forEach({ (key: String, value: Any) in Database.firestorefetchUserWithUID(uid: key, completion: { (user) in self.users.append(user) }) self.filteredUsers = self.users self.collectionView?.reloadData() }) } } } }
yuiso
5 years ago
Hi Brian, I got this super super weird bug here: I press anywhere on the screen, the DonthaveAccount button or AlreadyHaveAccount button will be triggered. It's nothing to do with my code I think. However, this bug only appares on ihpone 7 simulator. I change to iphone8 and it is totally fine. Yeah I can just use iphone8 simulator but anyway, it's too weird...
Santa
5 years ago
Hello mr B Don´t know if you talked about it yet here, but the bug after filtering performed and images for the users is changing when you search and delete text, you can see it clearly in the end of your video if you look on Dummy3 and check the image change when you search for a user. Any quick fix to that? =)
Santa
5 years ago
Another bug is that after dismissing the collectionView (my project doesn't look like this, im dismissing into the customTabBar) and returning into UserSearchController the SearchBar has defaulted back to white background, it seems like.. UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).backgroundColor = .gray is not getting called again, any tips?
shubhamsaurav
4 years ago
Hey Brian, I was having problems in fetching users in UserSearchController The error was :- Listener at /users failed: permission_denied Failed to fetch users for search: Error Domain=com.firebase Code=1 "Permission Denied" UserInfo={NSLocalizedDescription=Permission Denied} So I googled the problem and learnt that I need to change my security rules in firebase database. Earlier I was facing problem in listening at posts node and I changed the rules will allowed every users to Listen at posts node. In this case I have changed the rules to allow every users to listen to the users node. My new security is like this:- { "rules": { "users": { ".read" : "auth != null", ".write" : "auth != null", "$uid": { ".read": "$uid === auth.uid", ".write": "$uid === auth.uid" } }, "posts":{ ".read" : "auth != null", ".write" : "auth != null" } } } And everything is working fine. But Is this the best solution? Have you faced the same problem?
Goldor
4 years ago
Hello shubhamsaurav, I have also run into the same issue, and wanted to know how to secure my database properly right away (instead of fully opening the gates with read and write = true, as some people on the web suggest). The following article is really helpful: https://firebase.google.com/docs/database/security/securing-data?authuser=0 According to it, the shallowest rules override any rules below them, meaning that your "$uid" rules are overridden by the "auth != null" rules you set above them. The database access logic is that any user can read other users and posts, but can only write on his own account and posts, so the following security should be implemented: { "rules": { "users": { ".read": "auth != null", "$uid": { ".write": "$uid === auth.uid" } }, "posts": { ".read": "auth != null", "$uid": { ".write": "$uid === auth.uid" } } } } The only problem I can foresee (having only completed the course until the current video) is that a user wouldn't be able to write on another user's post to add a comment. You'd just need to use the logic you already implemented in your comment above ("write" : "auth != null"). Cheers!
Boula
4 years ago
Hey Brian, What's up ?! I have a little question about the sorting algorithms you used on the users array ?! Are the users sorted fully by just comparing (username), what about profileImageUrl and uid .... are they also getting swiped ?! or we need to conform to Comparable protocol ?! Thanks...
Daniel Peach
4 years ago
First of all: love these tutorials. But, I do wish you wouldn't keep glossing over concepts, like lazy loading. Or at least link to another video or article explaining it. Great content, though, best around!
Brian Voong
4 years ago
Daniel Peach
4 years ago
Perfect thanks so much!
johnsoa7
4 years ago
Hi Brian, Upon scrolling through the collection view, it appears that the profile images are displaying incorrectly and simply showing the same image. Would be much appreciated if you could suggest what the issue may be. Thanks, Abraham
astericky
4 years ago
Hi Brian, I'm not sure why you didn't implement this with just the user or make it so the user model can just create a user with less initial information and pass default information for the rest of the information....as opposed to having userId? and user? properties...
Cinquain
4 years ago
Video was litm
diegoseb
3 years ago
Hi Brian, Whats the difference between sorting by using the "common" { $0.username > $1.username } and the { ... u1.username.compare(u2.userName) == orderedAScending } ? Thank you.
Brian Voong
3 years ago
HELP & SUPPORT