How to retrieve certain childByAutoId() key - ios

I have looked around for a while, with no luck. I need to get the string value of a certain dictionary key in firebase.
If you look at the image below,I need that key on top, and need to set it equal to a string, that I can segue to other viewcontrollers so when a user wants to make a post under the sharers for example, I go into the right value based on the key, then to sharers, where I can add values. Thanks, also I do not need all values, just once I have observedWithSingleEvent, I need to get the key of each page or dictionary.
my code:
let ref = FIRDatabase.database().reference()
ref.child("Notes").queryOrderedByKey().observeSingleEvent(of: .value, with: { snapshot in
if let pagers = snapshot.value as? [String : AnyObject] {
let numb = snapshot.key //what I want
for (_, val) in pagers {
if let useri = val["postUsername"] as? String {
if useri == FIRAuth.auth()?.currentUser?.uid {
let bindfl = Page()
if let title = val["title"] as? String, let descript = val["description"] as? String,
let sharers = val["sharers"] as? [String], let poster = val["postUsername"] as? String, let setter = val["setter"] as? String, let creatorName = val["creatorName"] as? String {
bindfl.title = title
bindfl.descriptions = descript
bindfl.setter = setter
bindfl.sharers = sharers
bindfl.usernameOfBinder = poster
bindfl.creatorName = creatorName
bindfl.theBit = numb
self.pages.append(bindfl)

Well you can do it like this, when you add data to the database
let key = ref.("Notes").childByAutoId().key
let notes = ["userName": userName,
"description": description,
"title": title,
"author": author,
"keyID": key]
let childUpdates = ["/Notes/\(key)": notes]
ref.updateChildValues(childUpdates)
After that you can, get the key like this
bindfl.title = title
bindfl.descriptions = descriptions
bindfl.userName = userName
bindfl.author= author
bindfl.keyID= keyID
Hope it worked.

ref.child("Notes"). observeSingleEvent(of: .childAdded, with: {snapshot in
print("\(snapshot.key)")
})
Will give you the autoID key of every entry in the table
ref.child("Notes").queryOrdered(byChild: "creatorName").queryEqual(toValue: "posterName").observeSingleEvent(of: .childAdded, with: {snapshot in
var postID = snapshot.key
//update post different post using retrieved ID
let infoToAdd = ["newPostStuff" : true]
FIREBASE_REF!.child("Posts/\(postID)").updateChildValues(infoToAdd)
})
Will give you the auto ID of every post by a given creator and then update values on a different table with the retrieved key

Related

sending Firebase value to text fields

I have a view controller with three text fields. When the user uses the app for the first time, they enter some information in those text fields and press done, then the information goes to Firebase database:
FIRDatabase.database().reference().child("info").child(self.loggedInUser!.uid).setValue(saveObject)
However, the user also has the ability to edit those three text fields. As of now, when the user edits one text field and clicks done. The information of the non-edited text fields appear in their own text fields and then the user has to click the done button again for the edited text field to be sent to Firebase:
if City.text==""
{
FIRDatabase.database().reference().child("info").child(self.loggedInUser!.uid).observeSingleEvent(of: .value, with: { (snapshot:FIRDataSnapshot) in
if let postsDictionary = snapshot .value as? [String: AnyObject] {
let city = postsDictionary["City"] as? String ?? ""
self.City.text = city
}})
}
if Major.text==""
{
FIRDatabase.database().reference().child("info").child(self.loggedInUser!.uid).observeSingleEvent(of: .value, with: { (snapshot:FIRDataSnapshot) in
if let postsDictionary = snapshot .value as? [String: AnyObject] {
let major = postsDictionary["Major"] as? String ?? ""
self.Major.text = major
}})
}
if College.text==""
{
FIRDatabase.database().reference().child("info").child(self.loggedInUser!.uid).observeSingleEvent(of: .value, with: { (snapshot:FIRDataSnapshot) in
if let postsDictionary = snapshot .value as? [String: AnyObject] {
let college = postsDictionary["College"] as? String ?? ""
self.College.text = college
}})
}
if College.text=="" || Major.text=="" || City.text==""
{
FIRDatabase.database().reference().child("info").child(self.loggedInUser!.uid).observeSingleEvent(of: .value, with: { (snapshot:FIRDataSnapshot) in
})
}else{
if let City = City.text{
if let Major = Major.text{
if let College = College.text{
let saveObject: Dictionary<String, Any> = [
"uid": uid,
"City" : City,
"Major" : Major,
"College" : College
]
FIRDatabase.database().reference().child("info").child(self.loggedInUser!.uid).setValue(saveObject)
I don't think this is very user-friendly, I would like the user to edit whatever text field they want and I do not want the non-edited text field values to appear in their text fields and I would like the user to click on the done button once for the newly edited text field value to be sent to firebase.
Just create this func in viewdidload. This will load your current properties in firebase. You should adopt the UITextFieldDelegate and add the function textDidBegin which then you can make the textField (sender as! textField class) blank instead of having these loaded properties.
func reloadFirDatabase()
{ FIRDatabase.database().reference().child("info").child(self.loggedInUser!.uid).observeSingleEvent(of: .value, with: { (snapshot:FIRDataSnapshot) in
if let postsDictionary = snapshot .value as? [String: AnyObject] {
let city = postsDictionary["City"] as? String ?? ""
let major = postsDictionary["Major"] as? String ?? ""
let college = postsDictionary["College"] as? String ?? ""
if City.text.isEmpty {
self.City.text = city
{
if Major.text.isEmpty {
self.Major.text = major
}
if College.text.isEmpty {
self.College.text = college
}
}})
}
When you press done you should still load this in:
if let City = City.text{
if let Major = Major.text{
if let College = College.text{
let saveObject: Dictionary<String, Any> = [
"uid": uid,
"City" : City,
"Major" : Major,
"College" : College
]
FIRDatabase.database().reference().child("info").child(self.loggedInUser!.uid).setValue(saveObject)
I can guarantee you that doing it this way you only need to press the done button once.

Update Firebase data in tableView cell on tap

I am using Firebase real time database to display posts in a tableView. I want to increase the number of likes of a specific post when the user double taps the corresponding cell.
I got the double tap working and am already printing out the correct indexPath.
override func viewDidLoad() {
super.viewDidLoad()
// double tap
let doubleTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap(sender:)))
doubleTapGestureRecognizer.numberOfTapsRequired = 2
postTableView.addGestureRecognizer(doubleTapGestureRecognizer)
}
And here's what I tried according to the Firebase documentation to update the likes:
func handleDoubleTap(sender: UITapGestureRecognizer) {
let touchPoint = sender.location(in: postTableView)
if let indexPath = postTableView.indexPathForRow(at: touchPoint) {
print(indexPath)
let post = posts[indexPath.row]
let oldLikes = post.likes
let newLikes = oldLikes! + 1
let postUpdates = ["\(post.likes)": newLikes]
database.updateChildValues(postUpdates)
postTableView.reloadData()
}
}
It doesn't throw any errors but is not working.
This is the database structure:
And here's how I declared the database:
struct post {
let author : String!
let creationDateTime : String!
let content : String!
let likes : Int!
}
And in viewDidLoad
let database = FIRDatabase.database().reference()
This is how I create a post:
#IBAction func savePost(_ segue:UIStoryboardSegue) {
let addPostVC = segue.source as! AddPostViewController
let author = currentUser.displayName
let date = Date()
let formatter = DateFormatter()
formatter.dateFormat = "dd.MM.yyyy"
let dateResult = formatter.string(from: date)
let creationDateTime = "\(dateResult)"
let content = addPostVC.passTextContent
let likes = 0
let post : [String : AnyObject] = ["author" : author as AnyObject,
"content" : content as AnyObject,
"creationDateTime" : creationDateTime as AnyObject,
"likes" : likes as AnyObject]
database.child("Posts").childByAutoId().setValue(post)
}
And this how I retrieve the data in viewDidLoad
database.child("Posts").queryOrderedByKey().observe(.childAdded, with: {
snapshot in
let postID = (snapshot.value as? NSDictionary)?["postID"] as? String ?? ""
let author = (snapshot.value as? NSDictionary)?["author"] as? String ?? ""
let content = (snapshot.value as? NSDictionary)?["content"] as? String ?? ""
let creationDateTime = (snapshot.value as? NSDictionary)?["creationDateTime"] as? String ?? ""
let likes = (snapshot.value as? NSDictionary)?["likes"] as? Int ?? 0
self.posts.insert(post(postID: postID, author: author, creationDateTime: creationDateTime, content: content, likes: likes), at: 0)
self.postTableView.reloadData()
})
You have a problem with your database reference. When you do let database = FIRDatabase.database().reference() then you are refering to the main node in your database structure. This means that you will be working with the structure under the root in your database Json. The only child of it will be the Posts key.
When you do
let postUpdates = ["\(post.likes)": newLikes]
database.updateChildValues(postUpdates)
you are trying to update the value under the root node, which clearly does not exist. The only reference it can find is the key Posts.
In order to perform the update in the correct place, you could get child references from your main reference, especially one to the post you are interested in updating.
For example, you could do the following:
let postReference = database.child("Here goes the post Id").
Then, you will be able to use updateChildValues correctly on this new reference, since it will be updating the specific post.
Another thing that may be used wrong is the dictionary that is being sent to the updateChildValues. The structure of the dictionary that you have to provide is the following:
["key that you want to update": new value]
So in your case, instead of providing the previous like count and the new like count, you should provide a dictionary as the following:
let postUpdates = ["likes": newLikes]

Unable to get keys from firebase database

I have been pondering for the longest time in my student programmer life. I would like to know
I added the keys using autoChildId.
How to get keys from firebase database swift 2? I know how to get from Android using .getKeys()
My best friend, Google, taught me to use allKeys. However, my friendship is on the verge of in despair right now as I received the following msg that our relationship with .allKeys will always fail ( see image below). Haish...
I need this in order to show the data from Firebase Database into my tableview cos I believe this is the issue to a empty table just like how my heart is for my project. No heart.
Here is how my firebase database looks like:
Here is my code:
func findPlaceToEat(){
print("inside findPlaceToEat()")
print("Plan price level")
print(planPriceLevel)
print("End of price level")
ref = FIRDatabase.database().reference()
ref.child("places_detail").child("price_level").child(planPriceLevel).observeEventType(.ChildAdded, withBlock:{
(snapshot) in
if let dictionary = snapshot.value?.allKeys! as? [String: AnyObject]{
let PlaceObj = placeObj(place_name: dictionary["place_name"] as! String, place_type: dictionary["place_type"] as! String, price_range: dictionary["price_range"] as! String, vegan_type:dictionary["vegan_type"] as! String , website: dictionary["website"] as! String)
print("Whatever")
print(PlaceObj);
//self.tableView.reloadData()
}
}, withCancelBlock: nil)
}
to get key from snapshot
snapshot.key
I got a workaround for my project, everyone please pray that my lecturer don't see this. :
What I did was inside the save button I retrieve the value from database and then save it back into Firebase Database.
ref = FIRDatabase.database().reference()
ref.child("hello").child("google! I need a part time job").child(planPriceLevel).observeEventType(FIRDataEventType.ChildAdded, withBlock:{
(snapshot: FIRDataSnapshot) in
if let dictionary = snapshot.value as? [String: AnyObject]{
let getPlaceObj = placeObj()
getPlaceObj.setValuesForKeysWithDictionary(dictionary)
self.PlaceObj.append(getPlaceObj)
print("Name " ,getPlaceObj.place_name)
}
let place_name = snapshot.value?.objectForKey("place_name") as! String
let place_type = snapshot.value?.objectForKey("place_type") as! String
let price_range = snapshot.value?.objectForKey("price_range") as! String
let vegan_type = snapshot.value?.objectForKey("vegan_type") as! String
let website = snapshot.value?.objectForKey("website") as! String
print(place_name, place_type, price_range, vegan_type, website)
let savePlan : [String: AnyObject] = ["place_name":place_name, "place_type":place_type, "price_range":price_range, "vegan_type":vegan_type, "website":website]
self.ref.child("can you place hire me as your intern? I am from Singapore!!!").child(self.user!.uid).childByAutoId().setValue(savePlan)
}, withCancelBlock: nil)
You need to define query orderbykey like bellow:
this.afd.list('/yourItems/', {query:{orderByKey :true}}).subscribe((elements) => {
elements.map(element=>{
console.log(element.$key);
})
});

How to make multiple observations with Firebase?

I need to make multiple observations, but I don't know how.
Here is my database structure:
"Posts" : {
"f934f8j3f8" : {
"data" : "",
"date" : "",
"userid" : ""
}
},
"Users" : {
"BusWttqaf9bWP224EQ6lOEJezLO2" : {
"Country" : "",
"DOB" : "",
"Posts" : {
"f934f8j3f8" : true
},
"Profilepic" : "",
"name" : "",
"phonenumber" : ""
}
I want to observe the posts and I write the code and it works great, but I also want to get the name of the user who posted this post but when I wrote save the name and use it it gives me null. Here is my code.
DataServices.ds.REF_POSTS.queryOrderedByKey().observe(.value,
with: { (snapshot) in
self.posts = []
if let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshot {
if let postsDict = snap.value as? Dictionary<String, AnyObject> {
let key = snap.key
let userID = "BusWttqaf9bWP224EQ6lOEJezLO2"
DataServices.ds.REF_USERS.child(userID).observeSingleEvent(of: .value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
let postusername = value?["name"] as? String ?? ""
})
print(" ------ User name : \(postusername) ------")
})
print(" ------ User name 2 : \(postusername) ------")
let post = Posts(postKey: key, postData: postsDict)
self.posts.append(post)
The first print statement prints the username, but the second one prints nothing.
Thanks in advance.
Firebase is asynchronous so you can't operate on a variable until Firebase populates it within it's closure. Additionally code is faster than the internet so any statements following a closure will occur before the statements within the closure.
The flow would be as follows
Query for the post {
get the user id from the post inside this closure
query for the user info {
create the post inside this second closure
append the data to the array inside this second closure
reload tableview etc inside this second closure
}
}
Something like this edited code
self.posts = []
myPostsRef.queryOrderedByKey().observe(.value, with: { (snapshot) in
if let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshot {
if let postsDict = snap.value as? Dictionary<String, AnyObject> {
let key = snap.key
let userID = "BusWttqaf9bWP224EQ6lOEJezLO2"
myUsersRef.child(userID).observeSingleEvent(of: .value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
let userName = value?["name"] as? String ?? ""
let post = Posts(postKey: key, postData: postsDict, name:userName)
self.posts.append(post)
})
}
}
}
})
You're not using the postusername inside the closure so I added that to the Posts initialization.
Also, the self.posts = [] is going to reset the posts array any time there's a change in the posts node - you may want to consider loading the array first, and then watch for adds, changes, or deletes and just update the posts array with single changes instead of reloading the entire array each time.
Edit:
A comment was made about the data not being available outside the loop. Here is a very simplified and tested version. Clicking button one populates the array from Firebase with a series of strings, clicking button 2 prints the array.
var posts = [String]()
func doButton1Action() {
let postsRef = ref.child("posts")
self.posts = []
postsRef.observe(.value, with: { (snapshot) in
if let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshot {
let value = snap.value as! String
self.posts.append(value)
}
}
})
}
func doButton2Action() {
print(posts)
}

how to retrieve child(array) inside another firebase child

I am trying to print array from the firebase. Actually if we tap a medication in a list(tableviewcontroller), it will show its specfic dosages. I got stucked to retrieve the dosages list. Here is my code to get data from firebase. Any help is appreciated. Thanks in advance. My firebase structure looks like this.. firebase img
func loadDataFromFirebase() {
databaseRef = FIRDatabase.database().reference().child("medication")
databaseRef.observeEventType(.Value, withBlock: { snapshot in
for item in snapshot.children{
FIRDatabase.database().reference().child("medication").child("options").observeEventType(.Value, withBlock: {snapshot in
print(snapshot.value)
})
}
})
You should take a look on firebase documentation https://firebase.google.com/docs/database/ios/read-and-write
but if I'm understanding your idea, you probably has a model class for your medications. So, to retrieve your data you should do like this for Swift 3.0:
func loadDataFromFirebase() {
databaseRef = FIRDatabase.database().reference().child("medication")
databaseRef.observe(.value, with: { (snapshot) in
for item in snapshot.children{
// here you have the objects that contains your medications
let value = item.value as? NSDictionary
let name = value?["name"] as? String ?? ""
let dossage = value?["dossage"] as? String ?? ""
let type = value?["type"] as? String ?? ""
let options = value?["options"] as? [String] ?? ""
let medication = Medication(name: name, dossage: dossage, type: type, options: options)
// now you populate your medications array
yourArrayOfMedications.append(medication)
}
yourTableView.reloadData()
})
}
Now that you have your array with all your medications, you just need to populate your tableView with this medications. When someone press an item on table you can just call prepareForSegue: and send your yourArrayOfMedications[indexPath.row].options to the next view
The solution is same as above but with a small change.
func loadDataFromFirebase() {
databaseRef = FIRDatabase.database().reference().child("medication")
databaseRef.observe(.value, with: { (snapshot) in
for item in snapshot.children{
// here you have the objects that contains your medications
let value = item.value as? NSDictionary
let name = value?["name"] as? String ?? ""
let dossage = value?["dossage"] as? String ?? ""
let type = value?["type"] as? String ?? ""
let options = value?["options"] as? [String : String] ?? [:]
print(options["first"]) // -> this will print 100 as per your image
// Similarly you can add do whatever you want with this data
let medication = Medication(name: name, dossage: dossage, type: type, options: options)
// now you populate your medications array
yourArrayOfMedications.append(medication)
}
yourTableView.reloadData()
})
}

Resources