FirebaseDatabase query issues in Swift - ios

So I am currently working on a clone like snapchat and I am sending pull requests to the server, but as for downloading, it is not going so well. I created a reference to the database that looks like this,
var recievers: FIRDatabaseReference{
return mainRef.child("pullRequests")
}
and then I have a viewController that parses the data (which I know isn't the best way to go about this but I'm just trying to get it working right now) and in there I have this
DataService.instance.recievers.observeSingleEvent(of: .value) {(recipients: FIRDataSnapshot) in
if let recipient = recipients.value as? Dictionary<String,AnyObject>{
var index = 0;
for(key,value) in recipient{
index = index+1
if let dict = value as? Dictionary<String,AnyObject>{
if let reciever = dict["recipents"] as? Dictionary<String,AnyObject>{
if let num = reciever["\(index)"] as? String{
let uid = num
recipientsArr.append(uid)
}
}
}
}
}
}
for i in 0...recipientsArr.count{
print(i)
}
I'm not getting any compiling errors but it is also not adding anything into the recipientsArr, can anyone help guide me in the right direction?
My Firebase looks like this:

You're not decoding the snapshot properly. Its unclear from your question what is the value event you want to observe - is it just a new recipient that was added? the whole pullRequest?
In any case you're observing the pullRequest reference and therefore in order to decode the snapshot:
if let pullRequest = recipients.value as? Dictionary<String,AnyObject>{
if let recipientsList = pullRequest["recipents"] as? Dictionary<String,AnyObject>{
for (_, value) in recipientsList {
if let uid = value as? String{
recipientsArr.append(uid)
}
}
}
}

The problem is that you are using the method observeSingleEvent to update the value in the database, when this method is only used to recieve data from the database, not updated. In other words, it read-only.
The way to update record in a firebase database works different than the read methods. You can use both methods setValue and updateChildValues to perform updates. They both work on a database reference.
To use the setValue method, you should do something like this. I'll assume that you already have a pullRequests object that you previously created from the information you fetched from the database and have it in a variable:
let previousRecipents = pullRequests.recipents
let allRecipents = previousRecipents.append(newRecipent) // Assuming preivousRecipents is an array and you have the new Recipent
recievers.child("recipents").setValue(allRecipents)
To use the updateChildValues, it works very similar.
let previousRecipents = pullRequests.recipents
let allRecipents = previousRecipents.append(newRecipent) // Assuming preivousRecipents is an array and you have the new Recipent
let parametersToUpdate = ["recipents": allRecipents]
recievers.updateChildValues(parametersToUpdate)
For further information on how to update, check the following link:
https://firebase.google.com/docs/database/ios/save-data
Hope it helps!

Related

Cannot retrieve comments from database (FIREBASE/IOS)

I'm kind of bashing my head at the moment because I can't seem to figure out the reason why my code isn't properly loading comments from the database, It's receiving the ID's for each comment for a post from the database (post_comments) but isn't able to retrieve any data?
func loadComments() {
let postCommentRef = Database.database().reference().child("post_comments").child("6AECB02A-CC97-4ECB-8A09-702E254D4CCD")
postCommentRef.observe(.childAdded, with: {
snapshot in
print("snapshot key")
print(snapshot.key)
Database.database().reference().child("comments").child(snapshot.key).observeSingleEvent(of: .value, with: {
snapshotComment in
//print(snapshotComment.value!)
if let dict = snapshotComment.value as? [String : Any] {
let newComment = Comment().transformComment(dict: dict)
self.fetchUser(uid: newComment.uid!, completed: {
self.comments.append(newComment)
self.tableView.reloadData()
print(newComment) <- trying to retrive data, I've posted below what the output of this is.
})
//let photoUrlString = dict["photoUrl"] as! String
}
})
})
}
in my code you can see that I've placed a little print function to see what data the code spits out, here's the output from the debug log.
snapshot key
L_sWOp0w1V8DaGSK7iK
snapshot key
L_sWQI70PogYAtwjla4
snapshot key
hello <-- this is a test uid I created in the DB, treat it like any other key listed above.
as you can see the outcome of the loadComments() function doesn't achieve much.
I'm not sure if it's needed but just in case it helps I've taken a screenshot of the database to show how it actually looks below.
if any further information is required please ask and I'll provide it, I've only provided what I believe is necessary, and I'm pretty certain it's due to the way I'm retrieving data from the database.
EDIT
After some playing around I've managed to get some kind of output from the second database call, which retrieves the key in the comments database, which is the same two that are in the post comments database however, the value returns null.
func loadComments() {
let postCommentRef = Database.database().reference().child("post_comments").child("6AECB02A-CC97-4ECB-8A09-702E254D4CCD")
postCommentRef.observe(.childAdded, with: {
snapshot in
print(snapshot.key)
Database.database().reference().child("comments").child(snapshot.key).observeSingleEvent(of: .value, with: { (snapshotComment) in
print("Snapshot value")
print(snapshotComment.value)
print("Snapshot.key")
print(snapshotComment.key)
//print(snapshotComment.value!)
//if let dict = snapshotComment.value as? [String : Any] {
// let newComment = Comment().transformComment(dict: dict)
// self.fetchUser(uid: newComment.uid!, completed: {
// self.comments.append(newComment)
// self.tableView.reloadData()
// print(newComment)
// })
//let photoUrlString = dict["photoUrl"] as! String
})
})
}
The outcome of this code is as follows..
L_sWOp0w1V8DaGSK7iK <-- these two come from the snapshot.key for post_comments
L_sWQI70PogYAtwjla4 <---^
Snapshot value
Optional(<null>)
Snapshot.key
L_sWOp0w1V8DaGSK7iK
Snapshot value
Optional(<null>)
Snapshot.key
L_sWQI70PogYAtwjla4
I'm going to keep my hopes up and try figure out the source of this issue, if nobody can provide an answer to this question I'm hoping to be able to find a way to answer it myself as I believe the database structure I'm attempting to build is a lot more efficient and provides a better user experience, if I'm wrong I'd appreciate knowing a better way :)
EDIT #2
I seemed to have resolved my issue, I've posted a detailed description below of how and what was causing the issue along with the code I am using after resolving the issue
So it seems the issue was something ridiculously simple like I had thought, however, not actually having worked with firebase before it slipped right over my head, anyway after taking a look in the firebase console at the database I noticed comments would show as this https://REDACTED/comments/-L_sWQI70PogYAtwjla4
in the database, after looking closely you can see that the id for the comment begins with a hyphen, but looking in the database it's self without looking at the URL wouldn't actually reveal this, so I've managed to resolve this issue with about 4 characters as follows
Database.database().reference().child("comments").child("-" + snapshot.key).observeSingleEvent(of: .value, with: {
as you can see the 4 characters I'm speaking of is "-" = which adds the hyphen to the database query and returns the correct values; I'm not sure if this is the best way but it works so I'm happy!
here's my code after all this fuss in hopes someone facing the same issue in the future will find this question and not have to go through what I have...
func loadComments() {
let postCommentRef = Database.database().reference().child("post_comments").child("6AECB02A-CC97-4ECB-8A09-702E254D4CCD")
postCommentRef.observe(.childAdded, with: {
snapshot in
print("snapshot key")
print(snapshot.key)
Database.database().reference().child("comments").child("-" + snapshot.key).observeSingleEvent(of: .value, with: {
snapshotComment in
//print(snapshotComment.value!)
if let dict = snapshotComment.value as? [String : Any] {
let newComment = Comment().transformComment(dict: dict)
self.fetchUser(uid: newComment.uid!, completed: {
self.comments.append(newComment)
self.tableView.reloadData()
print(newComment)
})
//let photoUrlString = dict["photoUrl"] as! String
}
})
})
}

Swift: how to retrieve data from firebase?

My structure in firebase is as follows:
app name
user ID
wins = 7
losses = 8
and my code to read the wins child node
ref = Database.database().reference().child(passUserID)
ref?.child("wins").observe(.childAdded, with: { (snapshot) in
//Convert the info of the data into a string variable
let getData = snapshot.value as? String
print(getData)
})
But it prints nothing.
To read data from Firebase you attach a listener to a path which is what creates a FIRDatabase reference. A FIRDatabaseReference represents a particular location in your Firebase Database where there is a key-value pair list of children. So in your case, you have created a Firebase reference to the key "wins" which only points to a value and not a key-value pair. Your reference was valid up to this point:
ref = Database.database().reference().child(passUserID)
//did you mean FIRDatabase and not Database??
This FIRDatabaseReference points to the key passUserID which has a key-value pair list of children ["wins":"7"] and ["losses":"8"] (NOTE: a key is always a string). So from your FIRDatabase reference, you create your observer as follows and read the value of "wins":
ref?.observe(.childAdded, with: { (snapshot) in
//Convert the info of the data into a string variable
if let getData = snapshot.value as? [String:Any] {
print(getData)
let wins = getData["wins"] as? String
print("\(wins)")
}
})
The Child added event will fire off once per existing piece of data, the snapshot value will be an individual record rather than the entire list like you would get with the value event. As more items come in, this event will fire off with each item. So if "losses" is the first record you might not get the value of "wins". Is this what you are trying to achieve? If what you really wanted to know is the value of "wins" at that particular location and to know if this value has ever changed you should use the .value observer as follows:
ref?.observe(.value, with: { (snapshot) in
//Convert the info of the data into a string variable
if let getData = snapshot.value as? [String:Any] {
let wins = getData["wins"] as? String
print("\(wins)") //check the value of wins is correct
}
})
Or if you just wanted to get the know the value of wins just once and you are not worried about knowing if there any changes to it, use the "observeSingleEvent" instead of "observe".
EDIT
I saw your image and now realize you might also have a problem with your reference. Your ref should actually be something like:
ref = FIRDatabase.database().reference().child("game-").child(passUserID)
You have obscured what "game" is but a valid reference to "wins" will include it.
SECOND EDIT
I will add the following so you can properly debug the problem. Use this pattern to observe the value and see if you get an error returned and what is says:
ref.observe(.value, with: { (snapshot) in
print(snapshot)
}, withCancel: { (error) in
print(error.localizedDescription)
})
Normally it will give you an error if you cannot access that Firebase location because of a database rule. It will also be a good idea to see if print(snapshot) returns anything as above.
You need this:
ref.child("YOUR_TOP_MOST_KEY").observe(.childAdded, with: { (snapshot) in
let keySnapshot = snapshot.key
//print(keySnapshot)
self.ref.child(keySnapshot).observe(.value, with: { (snapshot2) in
//print(snapshot2)
}) { (error) in
print("error###\(error)")
}
})

Firebase iOS - Snapshot suddenly returning null when I know a value exists

Code that has been running fine for weeks suddenly is returning a null value when I call snapshot.value. Here is a picture of my DB:
My code is:
_ = ref.child("profiles").child((empID as!FIRDataSnapshot).value as! String).child("nickname").observeSingleEvent(of: FIRDataEventType.value, with: { (snapshot) in
print(snapshot)
self.names.append((snapshot).value as! String)
})
When I print the ref that I'm trying to make the snapshot from, I copy and paste the link into my browser and it correctly takes me to this screen:
So I have no idea why when I print snapshot it says
Snap (nickname) <null>
when there clearly is a value there. Then it throws an exception in the line where I try to append the nickname to a list. Does anyone know how this is possible? Especially since I don't recall changing anything to do with this piece of code in weeks. While I did not change the code recently, the only thing I've done is upload my app to TestFlight and had a few people download, could that possibly cause any of this somehow? I doubt this is the case because my code retrieves a value from another snapshot before this particular call successfully. Thanks!
There may be a different/better way to do this, but for your purposes, the following will work:
First, create a Profile model in a Profile.swift file, like so:
import UIKit
class Goal: NSObject {
var nickname: String?
var type: String?
}
Now, you can do this:
let profiles = [Profile]()
ref.child("profiles").child(empID).observeSingleEvent(of: FIRDataEventType.value, with: { (snapshot) in
if let dictionary = snapshot.value as? [String : AnyObject] {
let profile = Profile()
profile.setValuesForKeys(dictionary)
for item in dictionary {
if item.key == "nickname" {
print(item)
// do whatever logic you wanna do with item here - item will be set to the value of key "nickname"
}
}
}
})

Cast from FIRRemoteConfigValue to unrelated type String always fails : Firebase, Swift

I know this is a duplicate of Cast from FIRRemoteConfigValue to unrelated type String always fails. But the accepted answer there is that it's just a bug.
Which i don't think it is.
According to another solution, I have to force-cast the datatype every time I retrieve or instantiate a variable. I was hoping to find a different and elegant solution to this.
Everything was working fine, but after I installed Pod 'FirebaseRemoteConfig', I am having this warning on every line I instantiate a variable with a Snapshot value that I receive.
Cast from FIRRemoteConfigValue to unrelated type String always fails
When I run my app, it crashes there.
Bugged Code
FIRDatabase.database().reference().child("Posts").observe(.value, with: {(recievedSnap) in
if recievedSnap.exists(){
if let dict = recievedSnap.value as? [String:AnyObject]{
for each in dict{
let str = each.value["text"] as! String //Line of warning(and crash when the app is run)
}
}
}
})
Working Code
FIRDatabase.database().reference().child("Posts").observe(.value, with: {(recievedSnap) in
if recievedSnap.exists(){
if let dict = recievedSnap.value as? [String:AnyObject]{
for each in dict{
if let eachValue = each.value as? [String:AnyObject]{
let str = eachValue["text"] as! String
}
}
}
}
})
I am looking for explanation as to:
What changed after Pod 'FirebaseRemoteConfig' installation that it started giving me this error?
Why am I required to force cast every time I initialize a variable?
Is there a better approach?
Finally got the solution...
Use valueForKey Instead of [] bracket access value, because FIRRemoteConfigValue dont have support to access value using []
Then all value goes away...
For Example
Warning code...
Below code give a warning...
let id = snapshot.value!["senderId"] as! String
let text = snapshot.value!["text"] as! String
let locationId = snapshot.value!["location"] as! String
Use Like this
let id = snapshot.value.valueForKey("senderId") as! String
let text = snapshot.value.valueForKey("text") as! String
let locationId = snapshot.value.valueForKey("location") as! String
Warming is not appear longer.....
NOTE: If you use like above then old code also working fine...

Firebase data comparison swift

hi I'm new to swift and i'm using firebase in my app. i want to get all the data under a child from firebase database and compare it with an already existing array to find the missing values and load them in tableview i had added the code i use to perform this and in that the for loop is called every time when new child is found and i want to perform that for loop after getting all the values from the firebase database. is there any way to perform this or is there any way to know whether the firebase had retrieved all the data. Thanks in advance
func fetchUsers()
{
ingredientMasterArr.removeAll()
refhandle1 = ref.child("ingredients").observeEventType(.ChildAdded, withBlock:
{ (snapshot) in
if let dictionary = snapshot.value as? [String : String]
{
let ingredients = IngredientsClass()
ingredients.id = dictionary["id"]
ingredients.ingredient_name = dictionary["ingredient_name"]
// ingredients.category
ingredientMasterArr.append(ingredients)
}
FilteredIngMasterArr.removeAll()
let temp = IngredientsClass()
for MasterID in ingredientMasterArr
{
if (ShopIngKeysArr .contains(MasterID.id!)){
print("if",MasterID.ingredient_name)
}
else
{
print("else",MasterID.ingredient_name)
temp.id = MasterID.id
temp.ingredient_name = MasterID.ingredient_name
FilteredIngMasterArr.append(temp)
}
}
self.tbl_ingMaster.reloadData()
})
}
Using the .Value event type instead of .ChildAdded should give you all the results at once:
refhandle1 = ref.child("ingredients").observeEventType(.Value, ...
Read the firebase documentation on retrieving data for more details.

Resources