Get data from Firebase database with conditions using Swift - 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.

Related

Request result structure firebasedatabase Swift

Looking to retrieve value of custom class from a snap in swift like i do in java , i use Firebasedecoder .
Works fine but i need the following structure
{
username = uiii;
email = test#rom.com
..}
If i make ordered requests like .queryOrdered(ByCHild:email).queryEqual("uiii"), i get the resquest with a previous node :
{
"hjhj"= {
username = uiii;
email = test#rom.com
..} }
Looking for a way to either remove the uneccessary values or to have the correct snap structure.
When you execute a query against the Firebase Database, there will potentially be multiple results. So the snapshot contains a list of those results. Even if there is only a single result, the snapshot will contain a list of one result.
To get to the individual node(s) in the result, you need to loop over snapshot.children, as shown in the Firebase documentation on listening for value events on a list of children.
Also see:
previous questions about looping over children
Get the data from all children in firebase using swift
Firebase queryOrderedByChild() method not giving sorted data for an alternative if you want to only receive a single child node and only once
In short, if you have extra data at the same level and that makes decodeFirebase crash, you still can use it:
let value = snapshot.value
let modifiedValue:NSMutableDictionary = (value as AnyObject).mutableCopy() as! MutableDictionary
You then can remove elements by key: modifiedValue.removeObject(forKey: test)
and then apply decode.
custom class USER with all values in the pictures
import Foundation
import SwiftUI
import Firebase
import CodableFirebase
//knowing the userid , clean beautiful result with Firebasedecoder
func cleanResultWithCodebableFirebase(){
ref.child("3oleg").observeSingleEvent(of: .value, with: { snapshot in
guard let value = snapshot.value else { return }
do {
let user = try FirebaseDecoder().decode(User.self, from: value)
print(user.getUser_id())
} catch let error {
print(error)
}
})
}
not knowing userID dirty result
func customwithdirtylists(){
let query = ref.queryOrdered(byChild: Strings.field_username).queryEqual(toValue: "uiiii")
query.observeSingleEvent(
of: .value, with: { (snapshot) -> Void in
for child in snapshot.children {
let childSnapshot = snapshot.childSnapshot(forPath: (child as AnyObject).key)
for grandchild in childSnapshot.children{
let grandchildSnapshot = childSnapshot.childSnapshot(forPath: (grandchild as AnyObject).key)
//possible from here to get the key and values of each element of the custom class
}
}
})
}
This is the code i use in both cases, direct request or when ordered . No list visible when direct with the help of firebase decode .Ugly way to rebuild custom class thru looping . I m sure there are more elegant ways to do it especially when all i need is just remove one value of the direct result to have a clean result

Annoying issue regarding indexOn in Firebase rules

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.

Data failed to be returned from firebase [swift]

Firebase not returning data for a given record, despite it being present in the db .
I have some data in firebase that looks like this (2 records to be exact), and conforms to this structure
{
users : [
SOmeBig0lDID:{
credentials:{
name:"bob"
number:"+10778727737"
}
}
..... other users
]
}
In my app i am iterating over the phone numbers in my contact list and issuing a search for each number to identify which is a user. When i issue the search, i get back a value for one of my records, but not the other.
In terms of implementation, as you can see below, I am waiting for a search to complete before issuing another one , here is my code. Im wondering if it is just a corrupted record, in which case this is also very worrying.
I am also 100% sure that the phone number formatting is correct when the query is submitted to match that stored in firebase.
//get a list of correctly formatted phone numbers up here
func getuser(number:String,count:Int,total:Int){
print("Looking for :" + number+"|")
let usersRef = Database.database().reference().child("users")
let query = usersRef.queryOrdered(byChild: "credentials/number").queryEqual(toValue: number)
query.observeSingleEvent(of: .value, with: { snapshot in
for child in snapshot.children {
let snap = child as! DataSnapshot
var dict = snap.value as! [String: Any]
let creds = dict["credentials"]!
print(creds)
}
if count < total-1 {
getuser(number:finalNumbers[count+1], count:count+1, total:finalNumbers.count)
}
})
}
getuser(number:finalNumbers[0], count:0, total:finalNumbers.count)
I am expecting to get back the record for a number that i am querying , but i do not. I have verified that the number i am searching for is the number that is in the realtime database and have gone so far as to change the number in the realtime db to match exactly what i see the client issuing (it was doing this already however for completeness i wanted to ruled out the client doing some odd encoding) and yet still the record is not returned.
Oddly if i set the number of the record i am not getting returned, to the number of the record i am getting returned , i get both back. (both number fields have the same value).
If this is an issue with firebase more generally that others have experienced , please comment, i don't want to be using somethign that just doesn't work consistently.
any thoughts let me know, been stuck on this issue for a while.

How can I read the value of a Firebase database dictionnary created using .childByAutoId() in Swift?

I have a dictionary of dictionary of Strings stored in a Firebase database. It can be seen below.
As you can see, each entry is created using .childByAutoId() and contains two variables: text and tag.
I wish to be able to go through all of the entries, and compare the value of text with a variable saved locally in my app. I have tried many ways, but cannot find any solution that works. How should I proceed?
Thank you in advance for your help.
You need to observe database at specific reference and then convert a snapshot that will be send to you. The snapshot represents a fragment of your database at given path
let dbRef = Database.database().reference().child("messages")
dbRef.observeSingleEvent(of: .value) { (snapshot) in
for message in snapshot.children{
let msg = (message as! DataSnapshot).value //message as snapshot
//now you need to cast it to your structure([String:String])
let projectObj = Message(snapshotChild: msg as! [String:String])
//and do your comparison
}
}

How we get message of particular user to another in Firebase

I want to get message sent from a specific user to another. I am unable to achieve this. When I use the following code, I get the message from receiver. What I need is to get message particular recieverid to particular senderid.
My Database Snapshot
Here is my code:
Database.database().reference().child("chats")
.queryOrdered(byChild: "receiverid")
.queryEqual(toValue: "xEdACTcUWeOwrdIqjxeP5t5y4Kg2")
.observe(.childAdded, with: { snapshot in
let msgDict = snapshot.value as! [String: Any]
print(msgDict)
})
When using Firebase, you should structure your data to match the need of your views.
It looks like what you're trying to do is execute a query based on 2 properties and the Realtime Database can't do that yet. I recommend changing the structure of your data. Use your senderId as the key to each chat.
This way you'd have something like this:
"chats"{
"-L1RW456789":{
"messageKey":{
"name":"ddddd",
"receiverid":"xEdACTcUWeOwrdIqjxeP5t5y4Kg2",
"sender_id":"-L1RW456789",
"text":"Hello World"
},
"message2Key":{
"name":"eeeee",
"receiverid":"xEdAdasd23123",
"sender_id":"-L1RW456789",
"text":"How are you?"
}
}
}
(You can remove the "sender_id" attribute now, as it is now accessed by getting the key of the message's parent node)
And you'd be able to run your query like this:
Database.database().reference().child("chats").child("-L1RW456789")
.queryOrdered(byChild: "receiverid")
.queryEqual(toValue: "xEdACTcUWeOwrdIqjxeP5t5y4Kg2")
.observe(.childAdded, with: { snapshot in
let msgDict = snapshot.value as! [String: Any]
print(msgDict)
})