Read from firebase database with Swift - 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!

Related

Firebase realtime database query doesn't get new data until app reinstalled

In my app on sign up I'm checking if username is already taken.
I install the app, go to sign up, check if the username is free and everything works fine. If username is taken it tells me that.
But then when I created the account and trying to create another one with the same username, for some reason this username cant be found in database, even tho it's there.
Here is the code I use:
func singleObserveUser(withUsername username: String, completion: #escaping (UserModel) -> Void, onError: #escaping (String) -> Void) {
let queryUsername = username.lowercased().trimmingCharacters(in: .whitespaces)
usersRef.queryOrdered(byChild: Constants.UserData.UsernameLowercased).queryEqual(toValue: queryUsername).observeSingleEvent(of: .value) { (snapshot) in
if let _ = snapshot.value as? NSNull {
onError("No userdata found")
} else {
if let dict = snapshot.value as? [String: Any] {
let user = UserModel.transformDataToUser(dict: dict, id: snapshot.key)
completion(user)
} else {
onError("No userdata found")
}
}
}
}
If I restart app - everything is still the same.
If I delete app and install it again - everything works fine.
Seams like Firebase save some data on phone.
Thank you for your help!
If you have disk persistence enabled (the default on iOS and Android), the client stores data it has recently seen to allow it faster lookup later, and observeSingleEvent(of returns the value from that cache indeed.
If you want to ensure you have the latest value from the server, use getData instead as shown in the documentation on getting data once. Also check out Firebase Offline Capabilities and addListenerForSingleValueEvent for a longer explanation of the behavior.

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.

Get data from Firebase and display in TableViewCell as post

I don't know how to get data from Firebase to my UITableView. All tutorials I have been watching used Firebase Authentication, in their videos all worked out fine but while trying to replicate it, I failed.
Here is what I tried:
First there is my Database struct:
And here is my code:
func observePosts(){
let postsRef = Database.database().reference().child("posts")
postsRef.observe(.value, with: { snapshot in
var tempPosts = [Post]()
for child in snapshot.children {
if let childSnapshot = child as? DataSnapshot,
let dict = childSnapshot.value as? [String:Any],
let text = dict["text":""] as? String
{
let post = Post(text: text)
tempPosts.append(post)
}
}
self.posts = tempPosts
self.tableView.reloadData()
})
}
So my question is: How do I get for example the message from a database structure like this?
let text = dict["text":""] as? String {
let post = Post(text: text)
tempPosts.append(post) }
This is wrong. There is nothing like dict["text":""] . First you dont have any data for text keyword , Second you dont write this :""] , you can call as dict["text"].
I think you solution is let text = dict["title"] as? String . But you architecture is wrong. You can declare just one keyword . title 1 , title 2 is wrong. You have to set just title.
If you have followed YouTube tutorials, there's a high chance you did not modify your firebase rules to reflect on non-authenticated users. If you didn't, Firebase ignores every read/write request. To enable this, Edit your firebase rules by:
Set the rules to TRUE
{
"rules": {
".read": true,
".write": true
}
}
However, there's more to it. Don't do it this way unless you're in test mode. Google has some nice docs about it:
Visit https://firebase.google.com/docs/database/security to learn more about security rules.

Swift Firebase access data inside child snapshot (by childAdded)

I posted a question previously regarding how to access data inside a child snapshot, where I got a very well-working answer. However, this solution only allowed me to retrieve the data by value - and not my child. You see, I had a JSON tree-structure like this:
Players {
PlayerID {
Username
Rank
Achievements {
Rookie: yes
}
}
And then I realized that I really need multiple 'childByAutoId' under the 'Achievements' - that will look something like this:
Player {
PlayerID {
Username
Rank
Achievements {
autoID1 {
isAchieved: yes
}
autoID2 {
isAchieved: yes
}
}
}
So how would I go on trying to grab the very ChildValues of each childByAutoId? I know for a fact that this works with the 'ChildAdded' on observe Snapshot, however - this doesn't seem to be a feature here.
Here is the code I have right now:
if let childSnapshot = snapshot.childSnapshot(forPath: "Achievements") as? FIRDataSnapshot{
if let achievementDictionary = childSnapshot.value as? [String:AnyObject] , achievementDictionary.count > 0{
if let achieveMedal = achievementDictionary["Rookie"] as? String {
print(achieveMedal)
}
}
}
Help would be greatly appreciated!
How about a JSON tree structure like this:-
Achievements : {
achievement1 : true,
achievement2 : true,
achievement3 : false,
achievement4 : true,
}
For retrieving your achievements:-
if let childSnapshot = snapshot.childSnapshot(forPath: "Achievements") as? FIRDataSnapshot{
if let achievementDictionary = childSnapshot.value as? [String:AnyObject] , achievementDictionary.count > 0{
for each in achievementDictionary{
print(each.0) // achievement name
print(each.1) // isAchieved (true/false)
}
}
}
}
It's not advisable to add such deep nodes in your DB for navigation reason's .
But this code will also work for the childByAutoID case, i.e each.0 will be your autoID AND each.1 will become that id's corresponding dictionary.For deeper details of that dictionary just navigate through the dictionary

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.