I am trying to iterate over all keys under "Timetable" to get the key value and Name of those that have an approved value of "Yes".
So for the following JSON structure:
Timetable
Pikes_Lane_Primary_School_Bolton_UK
Approved: Yes
Name: Pikes Lane Primary School
Essa_Academy_Bolton_UK
Approved: No
Name: Essa Academy
Ladybridge_High_School_Bolton_UK
Approved: Yes
Name: Ladybridge High School
My desired output would be:
Pikes_Lane_Primary_School_Bolton_UK
Pikes Lane Primary School
Ladybridge_High_School_Bolton_UK
Ladybridge High School
This is the best I've managed to do over the last few hours:
let schoolDatabase = Database.database().reference().child("Timetable")
schoolDatabase.observeSingleEvent(of: .value, with: { (snapshot) in
for child in snapshot.children {
let schoolID = child as! DataSnapshot
//print(schoolID.key)
for grandchild in schoolID.children {
let varOne = grandchild as! DataSnapshot
print(varOne.key)
}
}
})
This brings back the following:
Approved
Name
Approved
Name
Approved
Name
let schoolDatabase = Database.database().reference().child("Timetable")
schoolDatabase
.queryOrdered(byChild: "Approved")
.queryEqual(toValue: "Yes")
.observeSingleEvent(of: .value, with: { (snapshot) in
let children = snapshot.children
.compactMap { $0 as? DataSnapshot }
children.forEach { tuple in
print(tuple.key)
if let tupleDictionary = tuple.value as? [String: Any] {
let name = tupleDictionary["Name"] as? String
print(name ?? "-")
}
}
}
)
Or if you are interested only in names (without key):
let schoolDatabase = Database.database().reference().child("Timetable")
schoolDatabase
.queryOrdered(byChild: "Approved")
.queryEqual(toValue: "Yes")
.observeSingleEvent(of: .value, with: { (snapshot) in
let children = snapshot.children
.compactMap { $0 as? DataSnapshot }
.compactMap { $0?.value as? [String: Any]}
.compactMap { $0["Name"] as? String }
children.forEach { name in
print(name)
}
}
)
Finally got there in the end!
let schoolDatabase = Database.database().reference().child("Timetable")
schoolDatabase.observeSingleEvent(of: .value, with: { (snapshot) in
for child in snapshot.children {
let schoolID = child as! DataSnapshot
let stringApproved = schoolID.childSnapshot(forPath: "Approved").value
let stringSchoolName = schoolID.childSnapshot(forPath: "Name").value
if stringApproved as? String == "Yes" {
print(schoolID.key)
print((stringSchoolName)!)
print((stringApproved)!)
}
}
})
Related
This question already has answers here:
Returning data from async call in Swift function
(13 answers)
Closed 2 years ago.
I'm a newbie to both Swift and Firebase, I don't Firebase is async connection and I don't know the best practice how to control the the program to wait for the return of data from Firebase and then proceed to next line.
Here is my code: I need to make two queries and once they were completed, then move on the the function prepareSelectedDftList, but the problem is the function is get called before Firebase return. Appreciated to give me some guidance how to fix it. Thank you.
ref = Database.database().reference().child(dftNode)
ref.observe(DataEventType.value, with: { (snapshot) in
// need to consider the workshop is still empty or not?
if snapshot.childrenCount > 0 {
// get defect list
for defect in snapshot.children.allObjects as! [DataSnapshot] {
let defectObj = defect.value as? [String: AnyObject]
let defectId = defect.key
let defectName = defectObj?["name"]
self.tmpDisplayDefectIdList.append(defectId)
self.tmpDisplayDefectNameList.append(defectName as! String)
self.tmpDefectSelected.append(0)
}
}
})
selectedDft = Database.database().reference().child(node)
selectedDft.queryOrderedByKey().queryEqual(toValue: passInCompId).observe(.childAdded, with: { (snapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot
let tmpkey = snap.key as String?
self.selectedDftId.append(tmpkey!)
}
self.prepareSelectedDftList()
})
You need to do like this:
ref = Database.database().reference().child(dftNode)
ref.observe(DataEventType.value, with: { (snapshot) in
// need to consider the workshop is still empty or not?
if snapshot.childrenCount > 0 {
// get defect list
for defect in snapshot.children.allObjects as! [DataSnapshot] {
let defectObj = defect.value as? [String: AnyObject]
let defectId = defect.key
let defectName = defectObj?["name"]
self.tmpDisplayDefectIdList.append(defectId)
self.tmpDisplayDefectNameList.append(defectName as! String)
self.tmpDefectSelected.append(0)
}
}
selectedDft = Database.database().reference().child(node)
selectedDft.queryOrderedByKey().queryEqual(toValue: passInCompId).observe(.childAdded, with: { (snapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot
let tmpkey = snap.key as String?
self.selectedDftId.append(tmpkey!)
}
self.prepareSelectedDftList()
})
})
OR Call both in parallelly
var i = 0
ref = Database.database().reference().child(dftNode)
ref.observe(DataEventType.value, with: { (snapshot) in
// need to consider the workshop is still empty or not?
if snapshot.childrenCount > 0 {
// get defect list
for defect in snapshot.children.allObjects as! [DataSnapshot] {
let defectObj = defect.value as? [String: AnyObject]
let defectId = defect.key
let defectName = defectObj?["name"]
self.tmpDisplayDefectIdList.append(defectId)
self.tmpDisplayDefectNameList.append(defectName as! String)
self.tmpDefectSelected.append(0)
}
}
i = i + 1
if i == 2{
self.prepareSelectedDftList()
}
})
selectedDft = Database.database().reference().child(node)
selectedDft.queryOrderedByKey().queryEqual(toValue: passInCompId).observe(.childAdded, with: { (snapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot
let tmpkey = snap.key as String?
self.selectedDftId.append(tmpkey!)
}
i = i + 1
if i == 2{
self.prepareSelectedDftList()
}
})
As the user types text into the searchBar the UISearchController has a delegate method to update search results:
func updateSearchResults(for searchController: UISearchController) {
guard let searchText = searchController.searchBar.text?.lowercased() else { return }
Database...usersRef
.queryOrdered(byChild: "username")
.queryStarting(atValue: searchText)
.queryEnding(atValue: searchText+"\u{f8ff}")
.observe( .childAdded, with: { [weak self](snapshot) in
let key = snapshot.key
guard let dict = snapshot.value as? [String: Any] else { return }
let user = User(userId: key, dict: dict)
self?.datasource.append(user)
})
}
That works fine.
When I normally paginate I use this procedure:
var startKey: String?
func handlePaginationForPosts() {
if startKey == nil {
Database...PostsRef
.queryOrderedByKey()
.queryLimited(toLast: 10)
.observeSingleEvent(of: .value, with: { [weak self] (snapshot) in
guard let children = snapshot.children.allObjects.first as? DataSnapshot else { return }
if snapshot.childrenCount > 0 {
for child in snapshot.children.allObjects as! [DataSnapshot] {
let postId = child.key
if child.key != self?.startKey {
guard let dict = child.value as? [String:Any] else { return }
let post = Post(postId: postId, dict: dict)
self?.datasource.insert(post, at: 0)
}
}
self?.startKey = children.key
}
})
} else {
let lastIndex = datasource.count
Database...PostsRef
.queryOrderedByKey()
.queryEnding(atValue: startKey!)
.queryLimited(toLast: 11)
.observeSingleEvent(of: .value, with: { [weak self] (snapshot) in
guard let children = snapshot.children.allObjects.first as? DataSnapshot else { return }
if snapshot.childrenCount > 0 {
for child in snapshot.children.allObjects as! [DataSnapshot] {
let postId = child.key
if child.key != self?.startKey {
guard let dict = child.value as? [String:Any] else { return }
let post = Post(postId: postId, dict: dict)
// I run a check to make sure the datasource doesn't contain the post before adding it
self?.datasource.insert(post, at: lastIndex)
}
}
self?.startKey = children.key
}
})
}
}
The problem here is when running a search I use:
.queryStarting(atValue: searchText)
.queryEnding(atValue: searchText+"\u{f8ff}")
But when paginating a post I use:
.queryOrderedByKey()
.queryEnding(atValue: startKey!) ...
self?.datasource.insert(post, at: lastIndex)
The startKey is the first key in the snapshot.children.allObjects.first and the lastIndex is the datasource.count.
Considering the search query is based on the search text and not a key, how can I paginate when I'm already using .queryEnding(atValue: searchText+"\u{f8ff}") instead of .queryEnding(atValue: startKey!)?
I need to track the key that was pulled from the db so that when I paginate I can run the next set of results from that particular key.
Firebase Database queries can only order/filter on a single property.
So what you can do is filter for the search criteria, and then limit to the firsts N results.
What you can't do is filter for the search criteria, skip the first N results, and get the next page.
The closest you can get, and something regularly done for cases such as this, is retrieve the first 2*N results when you need to show page 2. This wastes some bandwidth though, so you'll have to trade that off against how useful the pagination is.
I'm Trying to check if the rooms's value 'Owner' equals to the current user id if so then fetch all data including the key value and continue checking other children of 'rooms'
I was trying, but I fail finding the solution though it might seem easy so please help me with your suggestions or ideas. My code so far :
Database.database().reference().child("rooms").queryOrdered(byChild: "Owner").observeSingleEvent(of: .value, with: { (snapshot) in
let currentUser = Auth.auth().currentUser?.uid
if !snapshot.exists() {
print("No data found")
return
}
var rooms = snapshot.value as! [String:AnyObject]
let roomKeys = Array(rooms.keys)
for roomKey in roomKeys {
guard
let value = rooms[roomKey] as? [String:AnyObject]
else
{
continue
}
let title = value["title"] as? String
let description = value["description"] as? String
let roomPictureUrl = value["Room Picture"] as? String
let longitude = value["Longtitude"] as? String
let latitude = value["Latitude"] as? String
let dateFrom = value["Date From"] as? String
let dateTo = value["Date To"] as? String
let owner = value["Owner"] as? String
let myRooms = Room(roomID: roomKey,title: title!, description: description!, roomPicutreURL: roomPictureUrl!, longitude: longitude!, latitude: latitude!, dateFrom: dateFrom!, dateTo: dateTo!, owner: owner!)
self.rooms.append(myRooms)
self.tableView.reloadData()
print(snapshot.value)
}
})
You're missing the value in your query:
Database.database().reference()
.child("rooms")
.queryOrdered(byChild: "Owner")
.queryEqual(toValue: "STbz...")
.observeSingleEvent(of: .value, with: { (snapshot) in
See for this and more query operators, the documentation on filtering data.
Mark:- Swift 5
Database.database().reference().child("user")
.queryOrdered(byChild: "UserPhoneNumber") //in which column you want to find
.queryEqual(toValue: "Your phone number or any column value")
.observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.childrenCount > 0
{
if let snapShot = snapshot.children.allObjects as? [DataSnapshot] {
//MARK:- User Exist in database
for snap in snapShot{
//MARK:- User auto id for exist user
print(snap.key)
break
}
}
}
else if snapshot.childrenCount == 0
{
//MARK:- User not exist no data found
}
})
I'm trying to get the value of multiple children of my snapshot in order to append my cellDataArray by name and speed.
My code is working for name, but not for speed..
ref = FIRDatabase.database().reference().child("BasicInfo")
let query = ref?.queryOrdered(byChild: "Operator")
query?.observeSingleEvent(of: .value, with: { (snapshot) in
for child in snapshot.children.allObjects as! [FIRDataSnapshot] {
let name = child.key
let speed = child.childSnapshot(forPath: "Speed")
self.cellDataArray.append(cellData(mainText: name, Speed: ""))
self.tableView.reloadData()
}
})
This is my Firebase structure:
Try to access the value property of FIRDataSnapshot to get the Speed.
for child in snapshot.children.allObjects as! [FIRDataSnapshot] {
let name = child.key
if let dic = child.value as? [String:Any], let speed = dic["Speed"] as? Int
let operator = dic["Operator"] as? String {
print(operator)
self.cellDataArray.append(cellData(mainText: name, Speed: "\(speed)"))
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
I am currently building an app in Firebase and I want to get all the users pineapple rate.
This is the tree:
user1: uid1 {
fruits: {
apple: 3
pineapple: 5
}
}
user2: uid2 {
fruits: {
apple: 4
pineapple: 2
}
}
I tried this code:
var ref = FIRDatabase.database().reference()
ref.queryOrderedByChild("fruits")
.observeSingleEventOfType(.Value, withBlock: { (snapshot) in
if ( snapshot.value is NSNull ) {
print("not found")
} else {
for child in snapshot.children {
let rate = child.value["pineapple"] as! String
print(rate)
}
}
})
But it gives me an error of unwrapping Nil.
Picture of the structre:
This is supposed to be like this
var ref = FIRDatabase.database().reference()
ref.queryOrderedByChild("user2")
.observeSingleEventOfType(.Value, withBlock: { (snapshot) in
if snapshot.exists() {
for child in (snapshot.value?.allValues)! {
if let fruits = child["Fruits"] as? [String:String]{
let rate = fruits["pineapple"]
print(rate)
}
}
}
})
It seems this just needs a deep query?
let ref = self.myRootRef.child("parent_node")
ref.queryOrderedByChild("Fruits/pineapple").observeSingleEventOfType(.Value, withBlock: {
snapshot in
if ( snapshot.value is NSNull ) {
print("not found")
} else {
for child in snapshot.children {
let key = child.key as String
let dict = child.value["Fruits"] as! NSDictionary
let pineapple_count = dict["pineapple"] as! Int
print("key = \(key) count = \(pineapple_count)")
}
}
})
and the output is
key = uid_1 count = 1
key = uid_0 count = 3
key = uid_2 count = 21
Try out this code below (Xcode 8.3.3, Swift 3 and Firebase 3 )
var ref = Database.database().reference().child("fruits")
ref.observeSingleEvent(of: .value, with: {
(snapshot) in
if let fruitPost = snapshot.value as? Dictionary<String,AnyObject> {
for(key, value) in fruitPost {
if let fruitData = value as? Dictionary<String,AnyObject> {
if let fruits = fruitData["pineapple"] as? String{
let rate = fruits
print(rate)
}
}
}
}
Goodluck mate!