How to get child from Firebase nodes? - ios

I've been following this chat app tutorial with Swift, but now I want to be able to remove a post/message, so I want to be able to get to the specific child node to remove it, I've been trying like crazy a lot of things but nothing seems to work, I want to think I'm on the right path but I'm not pretty sure since I'm pretty new at coding.
I already got the Message Id, but in order to remove it I need to access to its parent.
#IBAction func buttonmessage(_ sender: Any) {
let feedMessageRef = Database.database().reference().child("feedMessages")
print(feedMessageRef)
}
})
That's pretty much my code, I can access the feedMessages node, but I can't access the next node. And this is how my firebase structure looks like. I want to be able to get the "-5440543187537959509", and somehow delete it.
feedMessages
-5440543187537959509
-LnmwFyZeTYbqLJgH6uf
date: 1567443980.238851
from:"N3gVh9oXhPcrxeJzPWGjtqB0ka42"
read: true
text: "Testing with mando"
to: "2LGYNCH4rFMJnKv3nQnvjcLyLhv1"
-LnmwIQg6WeVAHxrWt0x
date: 1567443990.295638
from: "N3gVh9oXhPcrxeJzPWGjtqB0ka42"
read: true
text: "Huh?"
to: "2LGYNCH4rFMJnKv3nQnvjcLyLhv1"
Ok, so I got this from reading the documentation and other Stack Overflow posts., now my code looks like this.
#IBAction func buttonmessage(_ sender: Any) {
let feedMessagesRef = Database.database().reference().child("feedMessages").observe(.value) { (snapshot) in
for childSnap in snapshot.children.allObjects {
let snap = childSnap as! DataSnapshot
print(snap.key)
let changedText = (snap.value as? NSDictionary)?["text"] as? String ?? "ChangedText"
print(changedText)
}
}
}
I managed to print the number that I wanted, which is a node from the firebase, but now I'm stuck on what's the next step to delete a post
Hope you guys can help me please, Thanks a lot!

Related

iOS callback if firebase query doesn't run (Swift Firebase)

I have a query running to check .childAdded at a location in my database.
It works well when data is found, however, if there is not data at the location, it can't fire the query and therefore this does not allow me to use snapshot.exists because it doesn't even run the query.
This is my current code
let favouriteRef = self.databaseRef.child("users").child(userID!).child("Favourites")
// Code doesn't run past this line when no data at location
favouriteRef.queryOrderedByKey().observe(.childAdded, with: { (snapshot) in
let favouriteID = "\(snapshot.value!)"
let usersRef = self.databaseRef.child("users")
usersRef.observeSingleEvent(of: .value, with: { (users) in
for user in users.children {
let favCleaner = UserClass(snapshot: user as! DataSnapshot)
if favouriteID == favCleaner.uid {
tempFav.append(favCleaner)
}
}
self.hasFavourites = true
self.tableView.reloadData()
self.usersArray = tempFav
self.collectionView.reloadData()
})
})
I would like to find a way to receive a callback if the query doesn't run (no data at location)
Thanks.
If there is absolutely no data at the location, then obviously this event trigger is not sufficient for you to get the data because this event only gets triggered when something gets added.
So you have two options
Add another trigger of type .observeSingleEvent(of: .value, with: { (snapshot) in
// Get the values and write the relevant actions
}
Or you can update this event to type .observe(.value, with: {snapshot in // write the relevant code
}
Both approaches have their advantage and disadvantage.
First approach will need you to write more code while minimising the number of triggers from your database to your UI. In second approach, there will be more triggers to the UI but it can be fairly easy to code.
From what I can see, you are first trying to establish whether data exists in the favorite node of your database and then comparing it to another snapshot. So if the number of delete or update events are relatively small, my suggestion is to go for approach two.

swift 4 / firebase Super Simple read / write. Can't read

Super newbie! I just want to practice reading and writing for Firebase. My write code works! I've consulted dozens of examples online and still can't get the read portion working.
As a newbie, I've also tried some simple debug techniques but no help.
Exactly how do I fix this code so that the read happens (and I know it happened because the code prints to terminal)?
I'd really like a Swift 4 based solution, thanks.
My repo
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var ref:DatabaseReference!
var refHandle:DatabaseHandle!
ref = Database.database().reference()
ref.child("test").setValue("name: Bruce")
//Nothing below works
refHandle = ref.child("test").observe(DataEventType.childAdded, with: { (snapshot) in
let info = snapshot.value as? String
print(info as Any)
})
}
Note that my Firebase DB is enabled for READ and WRITE. I have also tried observeSingleInsance (or whatever it is when you read just once).
I know the write works because i can see the data in the Firebase console
I believe your problem is in setValue("name: Bruce"), where you set the node "test" to "name: Bruce", as opposed to "name": "Bruce"
if you change that to say
updateChildValues(["name": "Bruce"])
surely it would work.
Go to your Firebase console, and perform following steps which is identify in image.
Read like that as you currently trying to listen to child add , so replace childAdded with value , Also you should wait until write process happens and then read , suppose launch app again for read only
refHandle = ref.child("test").observeSingleEvent(of: .value, with: { (snapshot) in
let info = snapshot.value as? String
print(info as Any)
})
Do you have this enabled? Then try changing it to
Database.database().isPersistenceEnabled = false
Otherwise try this and print the snapshot you get (You don't actually need the handle):
ref.child("test").observe(.value, with: { (snapshot) in
print(snapshot)
})

Retrieving my posts from firebase and display it on my collectionView Cells? ios

override func viewDidLoad() {
super.viewDidLoad()
getImageUrl()
}
func getImageUrl(){
ref.child("posts").queryOrderedByKey().observeSingleEvent(of: .value) { (snapchot) in
let postsss = snapchot.value as! [String : AnyObject]
for (_,posst) in postsss {
if let uid = posst["userID"] as? String{
if uid == Auth.auth().currentUser?.uid{
if let myPostURL = posst["pathToImage"] as? String{
self.imageURLs.append(myPostURL)
}
}
}
}
}
}
I want my code to go through all the posts on Firebase and then check if their userID matches the currentusers uid, if they matched which means they are my images. then send the URL in pathToImage to an array in my code called imageURLs()[ "" ].but I don't know how to to that??. I am using SDWebImage to display my images to the collectionView cell. i have tested it and it works fine if i copy and paste a random URL in the array called imageURLs[ "URL here" ]
I am very new to Swift and Firebase, so any help would be greatly appreciated!! :)
HERE IS AN IMAGE OF MY FIREBASE FILES.
https://ibb.co/bXLMcb
Psst! posts/pathToImage holds the URL so that's the one i want to retrieve.
users/urlToImage is just a profile picture. i don't really need it right now
To locate specific data within a node a Query is used.
While iterating over the nodes works, if there's a million nodes it's going to take a long time and tie up the UI while waiting for that to happen.
The bottom line is; if you know what you are looking for - in this case a uid - then a query is a super simple solution.
let postsRef = self.ref.child("posts")
let query = postsRef.queryOrdered(byChild: "userID").queryEqual(toValue: "uid_0")
query.observeSingleEvent(of: .value) { (snapshot) in
if snapshot.exists() {
for child in snapshot.children { //.value can return more than 1 match
let snap = child as! DataSnapshot
let dict = snap.value as! [String: Any]
let myPostURL = dict["urlToImage"] as! String
self.imageURLs.append(myPostURL)
}
} else {
print("no user posts found")
}
}
With the above code, we first create a reference to our posts node. Then a query that will only return this users (uid_0) posts.
We then iterate over the snapshot of posts and add them to the array.
This is much more efficient that loading and evaluating every node in the database.
See Sorting And Filtering data for more information.
You should think about storing an index of all your users posts somewhere in your database. That way you don't need to observe all posts every time. This is called denormalization. Firebase has an article in their docs about organizing your database.
Here's some information regarding firebase filtering in swift.
The best solution is to add a separate node that has a list of "post IDs" organized by user. Then you could observe that node, and only download each post specifically by the returned ID. Here's a link about flattening data structures in firebase. It would look something like this.
"posts":{
"somePostID":{
"timestamp": "0200231023",
"postContent": "here's my post content",
"authorUID" : "0239480238402934"
} ...
},
"postsByGivenUID":{
"someAuthorID":{
"somePostID": "true",
"somePostID": "true",
},
"someOtherAuthorID":{
"somePostID": "true",
"somePostID": "true",
"somePostID": "true"
}
}
This is actually a much bigger problem than just changing how you structure your code. For scalability sake, you're going to have to reevaluate how you structure the data in firebase altogether.
Then, you can nest your firebase query, sort of like this:
ref.child("postByGivenUID").child("Auth.auth().currentUser?.uid").observe(.childAdded) { (snapshot) in
ref.child("posts").child(snapshot.value).observeSingleEventOfType(of: .value) { (snap) in
// your actual post data will be here
// that way you won't be downloadin ALL posts EVERY time
}
}

Firebase not taking all arguments

My code goes as followed.
Once I get to the part where I am writing to the database it seems to skip over ContestName. Then it will record the contestdescription and user to the database. If I put contestDescription first before contestName then the contestDescription is missed but the name gets stored. Really funky bug. Any help would be appreciated.
NOTE: I tried a sleep but that didn't help at all.
#IBAction func SubmitContest(_ sender: Any) {
//Convert to text
let contesttitle = ContestName.text;
let contestdescript = ContestDescription.text;
//Some Firebase Stuff
let userID = Auth.auth().currentUser?.uid
let contestRef = ref.child("craftType").child("Custom")
let thisContest = contestRef.childByAutoId()
//Store to firebase
//Whatever one is first is not making it to firebase database
thisContest.setValue(["ContestName": contesttitle])
thisContest.setValue(["ContestDescription": contestdescript])
thisContest.child("User").setValue(userID)
}
Calling setValue on a location replaces all existing data at that location. So in this snippet:
thisContest.setValue(["ContestName": contesttitle])
thisContest.setValue(["ContestDescription": contestdescript])
The second line is replacing whatever the first line writes.
You should either combine the two:
thisContest.setValue(["ContestName": contesttitle, "ContestDescription": contestdescript])
Or use updateChildValues (which doesn't replace the entire data at the location, but only at the properties you specify):
thisContest.updateChildValues(["ContestName": contesttitle])
thisContest.updateChildValues(["ContestDescription": contestdescript])

Firebase Read to Swift NSArray / or String Swift 3.0

I am working on a project that reads from a Dictionary .plist that is located in the documents directory. I am currently migrating to Firebase. I have the "Write" working to -> Firebase. I also have the "Read" from <- Firebase working. The challenge that I am having is re-formatting the data the way I need it, in order to run it through my RegEx filter. I am not sure what to use to do this, a Parser or what... Just need some direction on the best way to pull the values out from the Firebase data that I read. I have spent about 10 hours trying different ways of formatting the Firebase data, but constantly get errors telling me that I can't change "Any" to "String" or "Any" to "Array". If you have not noticed, I am not a seasoned coder...
I am using Swift 3.0
This is the code that I have. (Note: I have the Firebase SDK installed and this code is just in the viewDidLoad func. for now). Also, I am using an NSObject Class that is outside of my viewDidLoad() for Post.
Thank you
var posts = [Post]()
class Post: NSObject {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//This is the code that reads from FireBase
let ref = Database.database().reference().child("List").queryOrderedByValue()
ref.observe(.value, with: { snapshot in
print(snapshot.value ?? "can't print Values")//snapshot.value is what prints out to the console
self.posts = []
if let snapshots = snapshot.children.allObjects as? [DataSnapshot] {
for snap in snapshots {
if let postDict = snap.value as? Dictionary<String, AnyObject> {
let post = Post()
post.setValuesForKeys(postDict)
self.posts.append(post)
}
}
}
})
}
The output of the code in the viewDidLoad() produces this output to the console
{"-KmUr43ZPycmz7G3IBlA" = "Adding something";
"-KmUr6M3F6HSEIAMbaVa" = "This is my next one";
"-KmUr8xe2vDtLMZn84kP" = "Emoji";
"-KmWaviTHnzD_EBatRU8" = "next definition";
"-KmYMTqVXHhanJkkId4r" = "Rich is Cool";}
I would like to pull out the values of the above output two different ways
and that is as an Array / NSMutableArray, and a String / NSMutableString
This is what I would like the Array to look like
["Adding something", "This is my next one", Emoji", "next definition", "Rich is Cool"]
This is what I would like the String to look like
Adding something, This is my next one, Emoji, next definition, Rich is Cool
Thank you so much for taking a look at this

Resources