Firebase - Order child value from low to high - swift

I want to order my tableView with values from Firebase from low to high. This is what I got so far:
Database.database().reference().child("Bier").queryOrdered(byChild: "Voor_prijs_int").queryStarting(atValue: 0).queryEnding(atValue: 10000).observeSingleEvent(of: .value) { snapshot in
print("test")
if let snapshots = snapshot.children.allObjects as? [DataSnapshot] {
print("test2")
for snap in snapshots {
print("test3")
if let postDict = snap.value as? Dictionary<String, AnyObject> {
print("test4")
let key = snap.key
let bier = BierModel.transformbier(dict: postDict, key: key)
self.bier_model.insert(bier, at: 0)
}
}
}
}
When I run this code it seems that it get stuck by print("test2"), because it never print
test3
I am not sure why this is, because I have got this code from a other project that worked.
Here is my Firebase structure:
Thanks

This code will sort the data based on the smallest value of variable to the largest:
self.bier_model.sort { $0.variable < $1.variable }

Related

Firebase Snapshot Isn't showing Data

Basically everything is working, except the showChild func is returning completion([]) because of the guard catData = Category(snapshot: catInfo). I am wondering why the guard let is returning completion. When I debug, catInfo does have 1 value as shown in my pic of database and I want to append catData.main to "cats". Below is code for the service method and Category model as well.
Firebase Database
static func showChild(completion: #escaping ([String]) -> Void) {
let ref = Database.database().reference().child("category").child(User.current.uid)
ref.observeSingleEvent(of: .value, with: { (snapshot) in
guard let snapshot = snapshot.children.allObjects as? [DataSnapshot] else {
return completion([])
}
var cats = [String]()
for catInfo in snapshot {
guard let catData = Category(snapshot: catInfo) else {
return completion([])
}
cats += catData.main
}
completion(cats)
})
}
import Foundation
import FirebaseDatabase.FIRDataSnapshot
class Category {
var key: String?
let main: [String]
init?(snapshot: DataSnapshot) {
guard !snapshot.key.isEmpty else {return nil}
if let dict = snapshot.value as? [String : Any]{
let main = dict["main"] as? [String]
self.key = snapshot.key
self.main = main ?? [""]
}
else{
return nil
}
}
}
The issue is pretty straightforward.
While your snapshot contains at least one node of data, it's not in a format that the Category init method understands. You're iterating over it's child nodes and in your screenshot, there's only one, with a key of 'main'
You are observing this node
fb_root
category
2ayHe...
and then you're iterating over it's child nodes which will be
main
0: Performance
so the key is 'main' and it's value is '0: Performance'
but your Category class is looking for a child node of 'main'
let main = dict["main"] as? [String]
There's not enough info to understand what will be contained in the rest of the structure so I can't tell you how to correct it, but at least you know what the problem is.
To clarify, this line
if let dict = snapshot.value as? [String : Any]
will make dict = [0: "Performance]

Issues when trying to remove the firebase reference

I am having some issues while trying to delete one of the tableView row - in my case I was trying to delete the data from Firebase and then reload the table view.
See the function below:
func deleteMeds() {
Database.database().reference().child("Meds_Database").child("UsersID").child((Auth.auth().currentUser?.uid)!).child("User_Medications").observe(DataEventType.childRemoved, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let medication = Meds()
medication.medName = (dictionary["Medication_Name"]) as! String
medication.medDosage = (dictionary["Medication_Dosage"]) as! String
medication.medEdit = (dictionary["Medication_Frequency"]) as! String
medication.medAlarm = (dictionary["Medication_Reminder"]) as! String
self.meds.remove(at: 0)
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
}
print(snapshot)
}, withCancel: nil)
}
I think I am getting confused with the Firebase Syntax... Can somebody help me? The database is like this:
I am sure someone can help
You only need to delete the relavant object not always index 0 here
self.meds.remove(at: 0)
So replace it with
self.meds = self.meds.filter{ $0 != medication }
and adopt the Equatable protocol

Showing just one image at the time from database (Swift and Firebase)

First of all, I am new in this, so please do not make fun of me :)
Basically, I am trying to show and Image of a product but if the client refuses the product this item will not appear on his account. That is why I am creating another table Rejected (setAcceptedOrRejected) where I put the ID of the product and the Id of the client so I wont see the item he rejected before.
What I tried here it was to get the List (Good) with all the items and the (Bad) with the rejected items. Then compare it to display the picture of the item again.
My problem is that I want to show only 1 picture at the time, if the client refuses then it will show the next one and so on but it wont show that picture again.
I hope you can really help me with this one.
Thank you
func updateImage() {
createListProductsBad ()
var badnot = ""
for bad2 in listProductsBad{
badnot = bad2
}
Database.database().reference().child("Products").child(bad2)queryOrderedByKey().observe(.childAdded, with: { snapshot in
let userInfo = snapshot.value as! NSDictionary
let storageRef = Storage.storage().reference(forURL: profileUrl)
storageRef.downloadURL(completion: { (url, error) in
do {
let data = try Data(contentsOf: url!)
let image = UIImage(data: data as Data)
self.productPhoto.image = image
}
catch _ {
print("error")
}
})
})
}
func setAcceptedOrRejected() {
let notThankyou = [ "ProductID": ProductId,
"UserID": userUID
] as [String : Any]
self.storyboard?.instantiateViewController(withIdentifier: "Home")
self.refProducts.child("Rejected").childByAutoId().setValue(notThankyou)
}
func createListProductsGood () {
Database.database().reference().child("Products").queryOrderedByKey().observe(.childAdded, with: { snapshot in
if !snapshot.exists() { return }
let userInfo = snapshot.value as! NSDictionary
let goodID = String(snapshot.key)
for prod in self.listProductsBad{
if (prod == goodID){
print("Not good **********************")
}else{
if (goodID != "" ){
self.listProductsGood.append(prod)
}
}
}
})
}
func createListProductsBad () {
Database.database().reference().child("Rejected").queryOrderedByKey().observe(.childAdded, with: { snapshot in
let userInfo = snapshot.value as! NSDictionary
let currentID = userInfo["UserID"] as! String
let badProduct = userInfo["ProductID"] as! String
if (self.userUID == currentID ){
self.listProductsBad.append(badProduct)
}
})
}
}
//These can also be swift's dictionaries, [String: AnyObject] or possibility arrays if done correctly. All depends on your style of programming - I prefer NSDictionaries just because.
let availableKeys: NSMutableDictionary = [:]
let rejectedKeys: NSMutableDictionary = [:]
//Might be a better way for you. Depends on what you are looking for.
func sortItems2() -> NSMutableDictionary{
for rejKey in rejectedKeys.allKeys{
//Removes if the rejected key is found in the available ones
availableKeys.remove(rejKey)
}
return availableKeys
}

Retrieving data from Firebase does not work

I have this code below in order to retrieve a list of restaurants and their data. However, it's not storing the data, and every time I try to return the array it returns nil. But if I print it, prints the data. Any suggestions?
func getRestaurants()-> Array<Restaurant>{
var baruri = [Restaurant]()
dataBaseRef.child("AthensRestaurants/Restaurants").observe(.value, with: { (snapshot) in
if let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshot {
print(snap)
if let restaurantData = snap.value as? Dictionary<String, AnyObject> {
let restaurant = Restaurant(restaurantData: restaurantData)
baruri.append(restaurant)
print(baruri)
}
}
}
})
return baruri
}
The firebase observe is an asynchronous callback function, so it will run after it is finished. In other words, your return baruri will always runs before the value got back. You can use completion handler to get the value you want.
var restaurants = [Restaurant]()
func getRestaurants(completion: #escaping (Array<Restaurant>) -> Void){
var baruri = [Restaurant]()
dataBaseRef.child("AthensRestaurants/Restaurants").observe(.value, with: { (snapshot) in
if let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshot {
print(snap)
if let restaurantData = snap.value as? Dictionary<String, AnyObject> {
let restaurant = Restaurant(restaurantData: restaurantData)
baruri.append(restaurant)
print(baruri)
completion(baruri)
}
}
}
})
}
// Call this function with call back
getRestaurants { restaurants in
self.restaurants = restaurants
}

IOS - Parsing objects from Firebase - Code running before download is completed

I am trying to parse data from Firebase into an array of objects, and upon completion display the text from the first object in the array. However, I can't work out/find a solution to stop the code continuing before the download is complete. So it proceeds to update the user's completion to true, without displaying the text. This is the function as is, the downloading and appending to array works fine, but it skips to displayNextInSeries() before it's finished...
func parseSeries (ref: String) {
FIRDatabase.database().reference().child("library").child("series").child(ref).observeSingleEvent(of: .value, with: { (snapshot) in
if let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshot {
print(snap)
if let pushSeriesDict = snap.value as? Dictionary<String, AnyObject> {
let key = snap.key
let push = PUSH_SERIES(pushKey: key, pushSeriesData: pushSeriesDict)
self.seriesArray.append(push)
}
}
}
})
print("\(ref) Series Count: \(self.seriesArray.count)")
displayNextInSeries()
}
The display next in series function sees the seriesArray.count = 0, so it doesn't update the texLbl:
func displayNextInSeries() {
if seriesProgress < seriesArray.count {
animateProgress(current: seriesProgress, total: seriesArray.count)
currentPUSH_SERIES = seriesArray[seriesProgress]
currentPUSH_SERIES.text = personaliseText(text: currentPUSH_SERIES.text)
textLbl.animateUpdate(currentPUSH_SERIES.text, oldText: previousText)
titleLbl.text = "\(currentPUSH_SERIES.title!)"
previousText = currentPUSH_SERIES.text
seriesProgress += 1
} else {
animateProgress(current: sessionProgress, total: sessionTarget)
titleLbl.text = ""
greetingPush()
seriesPlay = false
seriesProgress = 0
user.updateProgress(seriesName)
print(user.progress)
}
}
I may be doing something fundamentally wrong here. Your help is much needed and much appreciated! Thanks, Matt
The observeSingleOfEvent is an asynchronous call, calling the function inside the completionBlock will solve it,The problem is that your print function is being called even before observeSingleOfEvent is finished downloading data :-
func parseSeries (ref: String) {
FIRDatabase.database().reference().child("library").child("series").child(ref).observeSingleEvent(of: .value, with: { (snapshot) in
if let snapshot = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshot {
print(snap)
if let pushSeriesDict = snap.value as? Dictionary<String, AnyObject> {
let key = snap.key
let push = PUSH_SERIES(pushKey: key, pushSeriesData: pushSeriesDict)
self.seriesArray.append(push)
print("\(ref) Series Count: \(self.seriesArray.count)")
displayNextInSeries()
}
}
}
})
}