Cannot retrieve comments from database (FIREBASE/IOS) - 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
}
})
})
}

Related

How do I search for a particular item in my database using Swift and Firebase?

So I am building an app where I add certain words to my Firebase Database. When the user enters the word they want to add, I want to check if that word already exists in the database. If it does then I would show an alert. If not, I'll add it to the database. How would I do that with Swift? Any help would be appreciated. Thank you!
Here's the database structure:
speaktext-6-----
wordList
-LWQObIw1PKWJ_B9jNfp
word: "Water"
wordType: "Noun"
You need to take into account there may be a significant number of words so loading all of the words in will not only be slow as they have to loaded and then iterated over to find the word you are looking for, but it may also overwhelm the devices memory.
A simple solution is a Firebase Query - let Firebase do the heavy lifting and just return the node you want. It will be a LOT faster and won't overwhelm the device.
Here's a function that will tell you if a word exists within your firebase structure
func findWord(aWord: String) {
let ref = self.ref.child("wordList")
let query = ref.queryOrdered(byChild: "word").queryEqual(toValue: aWord)
query.observeSingleEvent(of: .value, with: { snapshot in
if snapshot.exists() {
print("found the word")
//you could expand on this to indicate it was a Noun etc
} else {
print("\(aWord) is not in the wordList")
}
})
}
Also review the Firebase Sorting and Filtering Data Guide
*this assumes a structure of
root
wordList
word_id_0 //created with .childByAutoId
word: "Water"
You just need to make a single event request on the word child, then you can verify if it .exists() and it will return if it's there or not.
let reference = Database.database().reference().child(<#child#>).child(<#Word#>)
reference.observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.exists() {
// handle word existing in database, show alert.
} else {
// handle word not existing in database, make a request to set the word in database.
}
})
According to your comments, you wanna iterate through every element on a child, you can do it by doing this:
let reference = Database.database().reference().child("wordList")
reference.observeSingleEvent(of: .value, with: { (snapshot) in
if let words = snapshot.value as? [String : [String : Any]] {
for word in words {
if let currentWord = word.value["word"] as? String {
if currentWord == "YOUR WORD HERE" {
// handle word in database.
return
}
}
}
// handle word NOT in database.
} else {
// handle empty array.
}
})

get a KEY, given a value, from Firebase in Swift

Have a registry of users, and we would like to input an email address, then return the UID.
Is there a way to do this in swift?
We would like the function to return this.
like we'd input user#user.com into the function and it will return gSVeU6....
Any tips and suggestions are really appreciated man.
Here is what the firebase JSON tree looks like
func findFriendsUIDFromFirebase(selectedFriendsEmail: String) {
print("Hey from findFriendsUIDFromFirebase called")
fir.child("registeredUsersOnPlatform").observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.exists() {
guard let allTheUsers = snapshot.value as? [String:String] else {
print("Something is wrong with this snapshot")
return
}
if let selectedUserUIDFromFirebase = allTheUsers.someKey(forValue: selectedFriendsEmail) {
//DO STUFF
basically in this way we download everything locally then loop through the dictionary, but am looking for a better way, one that doesn't involving downloading the whole thing. Maybe something with a .equals()?
At the same time, for some reason when printing the dictionary, it seems to be stuck at 100 key-value pairs. when there are like 300ish pairs on the actual table. It's some clipping somewhere.
You would need to perform a Firebase query for the specific value you are looking for:
let queryEmail = "Userone#user.com"
fir.child("registeredUsersOnPlatform").queryOrderedByValue().queryEqual(toValue: queryEmail).observeSingleEvent(of: .value) { (querySnapshot) in
for result in querySnapshot.children {
let resultSnapshot = result as! DataSnapshot
print (resultSnapshot.key)
}
}
You can also limit the amount of query results you would like with .queryLimited(toFirst: x)
If you want to get Key when create User in firebase you can get them in user callBack data like:
Auth.auth().createUser(withEmail: email, password: pwd) { (user, _) in
print(user?.uid)
}
Else if you want to get key from value in normal lists data so that use queryEqualToValue then print snapshot's child key

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

FirebaseDatabase query issues in Swift

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!

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

Resources