Data failed to be returned from firebase [swift] - 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.

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

How do I retrieve a random object from Firebase using a sequential ID?

I'm looking for an easy way to query my database in firebase using swift to retrieve a random object. I've read a lot of threads and there doesn't seem to be an easy way. One example showed it can be done be creating a sequential number but there's no information on how to create this sequential number for each record.
So either I need information on how to create a sequential number each time a record is created or if someone knows an easy way to retrieve a random record from a database that would be very helpful. In swift preferably.
My Database structure:
QUERY RANDOM OBJECT IN FIREBASE < VERY SIMPLE SOLUTION > SWIFT 4
One thing that you could try is to restructure your data like this:
- profiles
- 1jon2jbn1ojb3pn231 //Auto-generated id from firebase.
- jack#hotmail.com
- oi12y3o12h3oi12uy3 //Auto-generated id from firebase.
- susan#hotmail.com
- ...
Firebase's auto-generated id's are sorted in lexicographical order by key, when they are sent to Firebase, so you can easily create a function like this:
func createRandomIndexForFirebase() -> String {
let randomIndexArray = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9"]`
let randomIndex = Int.random(in: 0..<randomIndexArray.endIndex)
//In lexicographical order 'A' != 'a' so we use some clever logic to randomize the case of any letter that is chosen.
//If a numeric character is chosen, .capitalized will fail silently.
return (randomIndex % 2 == 0) ? randomIndexArray[randomIndex] : randomIndexArray[randomIndex].capitalized
}
Once you get a random index you can create a firebase query to grab a random profile.
var ref: DatabaseReference? = Database.database().reference(fromURL: "<DatabaseURL>")
ref?.child("profiles").queryOrderedByKey().queryStarting(atValue: createRandomIndexForFirebase()).queryLimited(toFirst: 1).observeSingleEvent(of: .value, with: { snapshot in
//Use a for-loop in case you want to set .queryLimited(toFirst: ) to some higher value.
for snap in snapshot.children {
guard let randomProfile = snap as? DataSnapshot else { return }
//Do something with your random profiles :)
}
}
Database.database().reference().child("profiles").observeSingleEvent(of: .value) { (snapshot) in
if let snapshots = snapshot.children.allObjects as? [DataSnapshot] {
// do random number calculation
let count = snapshots.count
return snapshots[Int(arc4random_uniform(UInt32(count - 1)))]
}

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
}
}

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.

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.