Annoying issue regarding indexOn in Firebase rules - swift

I have read practically every StackOverflow answer and none of them worked for my scenario since this is a frequent issue. My Xcode console is giving a very common warning when querying for data in Firebase. That warning is Using an unspecified index. Your data will be downloaded and filtered on the client. Consider adding ".indexOn": "username" at /users to your security rules for better performance
What I have tried was to first read the Firebase documentation understanding exactly what I am doing along with other answers as stated such as Why does this Firebase ".indexOn" not work?. Below, I have provided my security rules doing exactly as the message prompt; adding indexOn at /users but to no success. I have also provided my database users node and one function below.
{
"rules": {
".read": true,
".write": true,
"users":{
".indexOn": "username"
}
}
}
My Firebase database at /users in JSON format
"users":{
"5LYUynelLTcL8Bg9WNWGXV34YIq2" {
"email": "user1#gmail.com"
"username": "user1"
}
"9srk307kzxOW7j6dNmMaac9eYPu2" {
"email": "user2#gmail.com"
"username": "user2"
}
My function that I use in Swift
let ref = Database.database().reference().child("users").queryOrdered(byChild: "username").queryEqual(toValue: passedInFriendString)
ref.observeSingleEvent(of: .value) { (snapshot) in
print(snapshot)
}
I'm not sure where else to turn to. Any insight on if this is even the correct format to query for what I want would be great!

I solved it!
The thing I did not realize was that the above code in my question DOES print the snapshot successfully after adding the appropriate index definition on /users. My issue was realizing you need to loop through the snapshot if you want to further access data of the username snapshot I was querying for accordingly. That would look something like this
let ref = Database.database().reference().child("users").queryOrdered(byChild: "username").queryEqual(toValue: passedInFriendString)
ref.observeSingleEvent(of: .value) { (snapshot) in
for child in snapshot.children {
guard let snap = child as? DataSnapshot else {return}
if snap.hasChild("email") {
print("It has an email")
}
}
}
Thanks to Frank above for guiding me and confirming that I was on the right track. I'm happy to have learned something new and super efficient whenever I need to grab data.

Related

How do you queryOrderedByValue on a key that is auto-generated in Swift?

I need to queryOrderedByValue() on a node whose key is auto-generated. My database is structured as per pic below (/users-pings/$uid/$uid/"auto-id").
What changes can I make to my query below to achieve this?
REF_USERS_PINGS.child(currentUid).child(forId).queryOrderedByValue().queryEqual(toValue: "true").observeSingleEvent(of: .value) { (snapshot) in
if snapshot.exists(){
handler(true)
} else {
handler(false)
}
Firebase Database queries run on each child node under the location where you run them, so they autoskip the third level under user-pings in your case.
You just need to specify what property to order/filter on, which seems to be active here. So something like:
REF_USERS_PINGS.child(currentUid).child(forId).queryOrdered(byChild: "active").queryEqual(toValue: "true").observeSingleEvent(of: .value) { (snapshot) in
You need to use queryOrderedByKey() to return result related to that id only:
REF_USERS_PINGS.child(currentUid).child(forId).queryOrderedByKey().queryEqual(toValue: "-LH72MNIVX8o4KI3V9nL").observeSingleEvent(of: .value) { (snapshot) in
more info here:
https://firebase.google.com/docs/database/ios/lists-of-data#data_order

How to check if a Firebase DB node value is true using swift?

I have the following Firebase DB structure (see pic) which is created when a user sends a compliment to another user.
The compliment is saved under compliments with an auto-generated id
The compliment.key is also saved under users-compliments, under senderID/receiverID/then the "complimentID":"boolean" pair to indicate if it is "active"
I wish to check if an "active" compliment exists before being allowed to send another one to the same user.
But the following query results in a null output even though there is a child node with a value of 1.
What am I doing wrong here?
Query:
REF_USERS_COMPLIMENTS.child(currentUid).child(forId).queryEqual(toValue: "1").observeSingleEvent(of: .value) { (snapshot) in
print("snap: \(snapshot.value)")
}
Console output:
snap: Optional(<null>)
When using queryEqual() you have to combine it with an queryOrderedBy. In your case it would be queryOrderedByValue() because you want to compare the value:
REF_USERS_COMPLIMENTS.child(currentUid).child(forId).queryOrderedByValue().queryEqual(toValue: "1").observeSingleEvent(of: .value) { (snapshot) in
print("snap: \(snapshot.value)")
}
More information about this can be found in the docs.
Try this:
REF_USERS_COMPLIMENTS.child(currentUid).child(forId).observeSingleEvent(of: .value) { (snapshot) in
print("snap: \(snapshot.value)")
if let _ = snapshot.value as? NSNull {
// do your thing
}
}

Get data from Firebase database with conditions using Swift

I have such structure of DB:
As you see I have two collections: 'Threads' and 'Users'
I need to receive all threads where ownedId is wVlUM2Un9kNouOIlztKLvxxxPDh1 e.g.
Hi I had a similar scenario while working on a chatting application that used firebase as a backend service.
you can use a query as such, I did it through similar query
FireBase.Reference.threads
.queryOrdered(byChild: "ownerId")
.queryEqual(toValue: "YourUserId")
.observe(.value) { (snapshot) in
if let messages = snapshot.value as? NSDictionary {
// you will get all those threads where ownedId is what you need to fetch for
}
}
Hope this helps, please let me know if any corrections required.

Read from firebase database with Swift

I'm struggling to get the value I need from Firebase
I have this setup
MyAppName:
- version : 1.0
and I am trying to get it like so:
let refHandle = dbRootRef.observe(FIRDataEventType.value, with: { (snapshot) in
let postDict = snapshot.value as? [String : AnyObject] ?? [:]
print(postDict)
})
Can someone help me get the 1.0 from the database?
p.s - no errors and nothing in the console
try this
let ref = "path to your Firebase/version" //point directly to the version node
ref.observe(FIRDataEventType.value, with: { (snapshot) in
print(snapshot?.value) //prints 1
})
Testing rules: set to
{
"rules": {
".read": true,
".write": true
}
}
Do you have pod file configured? and also App Delegate configuration? Google Plist File Added? Getting a Value from Firebase is pretty straightforward,. Follow this tutorial and you would be ready to go! https://www.youtube.com/watch?v=joVi3thZOqc&index=10&list=PLl-K7zZEsYLn-elkHPhDuuwdCZ93BXnrB
Thats the only way I can help with the information you gave about your problem, hope it helps!

Firebase Swift .exist() not working

Hello I am using firebase on swift and having an issue with .exist()
I am trying to do a query and check for a value, if its there I do nothing, if it isn't I add it to the list. I am just trying to avoid duplicating data this way. Heres the code:
InfoCenter.ref.child("users/\(InfoCenter.userId)/following").queryOrderedByValue()
.queryEqualToValue(firstTextField.text)
.observeEventType(.Value, withBlock: { snapshot in
if snapshot.exists(){
self.displayAlert("You already follow that person!", Title: "Whoops")
print(snapshot.value!)
} else {
InfoCenter.ref.child("users/\(InfoCenter.userId)/following").childByAutoId().setValue(TheId)
InfoCenter.ref.child("users/\(TheId)/followers").childByAutoId().setValue(InfoCenter.userId)
print(snapshot.value!)
}
})
so to me everything looks right, but when it runs snapshot.exist() always returns false but when I print snapshot.value! I get null with arrows around it (I couldn't type the arrows because SO thought it was a tag then) . So I'm confused.. how is null considered exists? Can someone please show me what to change to fix this? Thanks!!
Edit:
To be clear following is a list of users. So with in following are autoId's that have links to other users. The whole purpose of the above query is to go through the autoId's and make sure that this person does not already follow that person. Here is a snapshot of the data structure I am trying to explain:
Can I suggest an alternative? This solution reads the value as the location in question. Big benefit here is that there's no query overhead.
Assume we want to see if we follow frank and if not, follow him.
let ref = InfoCenter.ref.child("users/\(InfoCenter.userId)/following")
ref.observeSingleEventOfType(.Value, withBlock: { snapshot in
if let person = snapshot.value as? String {
if person == "frank" {
print("you are following frank: creeeeepy")
} else {
print("you are not following frank, follow him")
}
} else {
print("node doesnt exist")
}
})
this will directly read the value at
users/some_user_id/following: "the value that's read (frank in this case)"
Edit: based on an updated question, the 'following' node should look like
users
your_uid
following
some_user_you_are_following_uid: true
another_user_you_are_following_uid: true
then you are simply checking to see if the path exists
let ref = InfoCenter.ref.child("users/\(InfoCenter.userId)/following")
let theUserRef = ref.child("some_user_you_are_following_uid")
theUserRef.observeSingleEventOfType(.Value, withBlock: { snapshot in
I think your query might not be be working user InfoCenter.userId might be an optional force unwrap and see if that return the snapshot.