Swift: Searching Firebase Database for Users - ios

I have been looking all over the internet and Stack overflow but haven't found anything that I understood well enough to implement into my solution.
There are many similar questions out there but none of the proposed solutions worked for me, so I'll ask you guys.
How do I search my Firebase database for usernames in swift?
In my app I have a view that should allow the user to search for friends in the database. Results should be updated in real time, meaning every time the user types or deletes a character the results should update. All I have so far is a UISearchBar placed and styled with no backend code.
Since I don't really know what is needed to create such a feature it would be cool if you guys could tell me what you need to tell me exactly what to do. (Database Structure, Parts of Code...). I don't want to just copy and paste useless stuff on here.
I would really appreciate the help.
EDIT:
This is my database structure:
"users"
"uid" // Automatically generated
"goaldata"
"..." // Not important in this case
"userdata"
"username"
"email"
"country"
"..." // Some more entries not important in this case
Hope I did it right, didn't really know how to post this on here.

Suppose the Firebase structure is like this
Example 1 :
users
-> uid
->otherdata
->userdata
->username : "jen"
-> other keys
-> uid2
->otherdata
->userdata
->username : "abc"
-> other keys
And to query based on username, we need to query on queryOrdered(byChild: "userData/username"). queryStarting & queryEndingAt , fetches all the names starting from "je" and this "\uf8ff" signifies * (any) .
let strSearch = "je"
baseRef.child("users").queryOrdered(byChild: "userData/username").queryStarting(atValue: strSearch , childKey: "username").queryEnding(atValue: strSearch + "\u{f8ff}", childKey: "username").observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot)
}) { (err) in
print(err)
}
If the username is directly below the users node, then try this
Example 2 :
users
-> uid
->username : "jen"
-> other keys
-> uid2
->username : "abc"
-> other keys
The query will be restructured as below,
let strSearch = "je"
baseRef.child("users").queryOrdered(byChild: "username").queryStarting(atValue: strSearch).queryEnding(atValue: strSearch + "\u{f8ff}").observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot)
})
Please note this method is case-sensitive . The search results for search String = "je" and "Je" will be different and the query will match the case.

Related

Problem with logic when it comes to storing dictionary values in firestore

I am trying to re-create the instagram follower and following functionality but there seems to be an error in logic. There is no error in code. What I am doing right now when the "follow" button is pressed, is to create a collection called "user-following", add the "current UID" as "document ID" and then store the following target users data as [targetuid: 1]. At the same time, I create a collection called "user-followers", add the "Target UID" as "document ID" and then store the followers data as [currentuid:1]. The issue here is that it works when it comes to following just one user. When I try to follow another, the existing following user data gets overridden with the new user whom I just followed instead of appending the data.
Example: Assume currentUser is A, user1 = B, user2 = C
When I follow user1 and user2 my database in firestore should be reflected as:
user-following -> A -> [B:1,C:1]
user-followers -> B -> [A:1]
user-followers -> C -> [A:1]
The above translates to collection -> documentID -> dictionaryvalues
The problem is that I do not get the above result. Instead when I follow user2, the value of user1 gets overridden. So there is only one dictionary value stored.
I know that the problem lies somewhere in the way I am trying to create a field under the document ID. I know I can create a dictionary and append values but I think that's a lot of code for an otherwise simple solution.
func follow(){
guard let currentUid = Auth.auth().currentUser?.uid else
{return}
guard let uid = uid else {return}
self.isFollowed = true
// Add followed user to current user-following structure
Firestore.firestore().collection("user-
following").document(currentUid).setData([uid:1])
// Add current user to followed user-follower structure
Firestore.firestore().collection("user-
followers").document(uid).setData([currentUid:1])
}
Never mind. Realised that I had to use merge.
Firestore.firestore().collection("user-
following").document(currentUid).setData([uid:1], merge: true)

Swift Firebase Query - No Results in Snapshot

I am trying to query our LCList object by the "name" value, as shown in this image. The name key is just on the next level below the object. There are no additional levels to any of its other values.
The code I am using to do the query is: (Keeping in mind listsRef points to the LCLList object)
listsRef.queryOrderedByKey()
.queryStarting(atValue: name)
.observeSingleEvent(of: .value, with: { snapshot in
The snapshot from this query comes back with nothing in its value. I have tried ordering the results by the name value as well, with the same result. I have inspected the values returned with only the queryOrderedByKey() method call, and they match what is in the database. The issue is obviously with the .queryStarting(atValue:) method call.
I'm really puzzled by why this is not working as the same query pointed to our LCLUser object, with nearly the same structure, does get results. The two objects exist at the same level in the "Objects" directory seen in the previous image.
Any help at this point would be appreciated. I'm sure there's something simple I'm missing.
That query won't work for the Firebase structure shown in the question.
The query you have is as follows, I have added a comment on each line detailing what each line does
listsRef.queryOrderedByKey() //<- examine the key of each child of lists
.queryStarting(atValue: name) //<- does that keys' value match the name var
.observeSingleEvent(of: .value, with: { snapshot in //do it once
and your current data looks like this
Objects
LCLLists
node_x
creator: "asdasa"
name: "TestList3"
node_y
creator: "fgdfgdfg"
name: "TestList"
so what's happening here is the name var (a string) is being compared to the value of each key (a Dictionary) which cannot be equal. String ≠ Dictionary
key value
["node_x": [creator: "asad", name: "TestList3"]
For that query to work, your structure would need be be like this
Objects
LCLLists
node_x: "TestList3"
node_y: "TestList"
My guess is you want to stick with your current structure so, suppose we want to query for all names that are 'TestList' using your structure
let ref = self.ref.child("LCLLists") //self.ref is a class var that references my Firebase
let query = ref.queryOrdered(byChild: "name").queryEqual(toValue: "TestList")
query.observeSingleEvent(of: .value, with: { snapshot in
print(snapshot)
})
and the result is a printout of node_y
node_y
creator: "fgdfgdfg"
name: "TestList"

Search Firebase Query with array of unique keys

I have my schema set as follows.
Now i want to send the a string chinohills7leavescafe101191514.19284 and want to check if there is any string in the Chino Hills or not.
I am confused to make any search query because i have not stored above string in fixed childKey
I know the schema should be like this but i cannot change the schema.
leaves-cafe
codes
Chino Hills
-Kw0ZtwrPjyNh1_HJrkf
codeValue: "chinohills7leavescafe101191514.19284"
You're looking for queryOrderedByValue. It works the same ways as queryOrderedByChild and allows you to use queryEqualToValue to achieve the result you need since you can't alter your current schema.
Here's an example
// warning: untested code - just illustrating queryOrderedByValue
let ref = Database.database().reference().child("leaves-cafe").child("codes").child("Chino Hills")
let queryRef = ref.queryOrderedByValue().queryEqual(toValue: "chinohills7leavescafe101191514.19284")
queryRef.observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.exists() {
print("value does exists")
} else {
print("value doesn't exist")
}
})
Your alternative option is to iterate over all nodes and check if the value exists manually as 3stud1ant3 suggested. However, note that this approach is both costy and a security risk. You would be downloading potentially a lot of data, and generally you shouldn't load unneeded data (especially if they're sensitive information, not sure if that's your case) on device; it's the equivalent of downloading all passwords off a database to check if the entered one matches a given user's.

Get a limited number of records in Firebase

I would like to query Firebase for records that match my conditions, but I want to only get a few of them. I am using Swift. Is this possible? For example, I have a query like this:
firebaseReference.child("array").queryOrdered(byChild: "userType").queryEqual(toValue: "family").observe(.value, with: { (snapshotVec) -> Void in
Storage.shared.numFamsInVec = snapshotVec.childrenCount
}
This will retrieve all the records whose userType is family, but say I only want to get half of them. How do I do this?
It certainly is. The magic is in the Firebase documentation for filtering data on iOS:
firebaseReference
.child("array")
.queryOrdered(byChild: "userType")
.queryEqual(toValue: "family")
.queryLimited(toFirs: 10)
.observe(.value, with: { (snapshotVec) -> Void in
Storage.shared.numFamsInVec = snapshotVec.childrenCount
}
Also see the Firebase reference documentation, which contains the magic incantation for Swift 3.

databaseRef Firebase withoud childByAutoID()

Guten Tag,
i'm uploading some text to firebase through my iOS Application, but i can't find a code, where i can give the App User not a random ID, but maybe the email for the id to upload or Name. I hope you understand what i mean.
Current Code:
let logininit : [String : AnyObject] = ["text4" : text4!, "text5" : text5!, "text6" : text6!]
let databaseRef = FIRDatabase.database().reference()
databaseRef.child("Logins").childByAutoId().setValue(logininit)
Now i want to remove this childByAutoID, and set it to, how i said, email or name of the user.
Firebase Database
EDIT
Resolved this Problem: databaseRef.child("Logins").child(The Email That You Want Here).setValue(logininit)
I think I understood what you meant, but I don't see reasons for you to do that. Usually when you have a new entry on some entity, you usually gives it a unique ID (UUID). So, I think if you use child(The Email That You Want Here), should work as you want:
databaseRef.child("Logins").child(The Email That You Want Here).setValue(logininit)

Resources