How to Firebase retrieve data below UID and auto ID In Swift - swift

[enter image description here][1]I'm trying to retrieve specific data from Database. I'd like to read all data in product_list
My Database
This is what i try but when i print listName. It show like this listName = nil
let refList = Database.database().reference().child("Users/Sellers")
refList.observe(DataEventType.value, with:{(snapshot) in
if snapshot.childrenCount>0{
self.listProduct.removeAll()
for lists in snapshot.children.allObjects as! [DataSnapshot]{
let userList = lists.value as? [String: AnyObject]
let listName = userList?["name"]
let listDetail = userList?["detail"]
let listPrice = userList?["price"]
print("key = \(listName)")
let list = ListModel(name: listName as! String?, detail: listDetail as! String?, price: listPrice as! String?)
self.listProduct.append(list)
}
self.tableList.reloadData()
}
})
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ViewControllerTableViewCell
let list: ListModel
list = listProduct[indexPath.row]
cell.lblName.text = list.name
cell.lblDetail.text = list.detail
cell.lblPrice.text = list.price
return cell
}
It have 4 things i want to retrieve
(details, name, price and product_image_url)

Right now your code is looping over the child nodes of /Users/Sellers, which is the nodes of each individual user. What you seem to want to do is include all nodes under the product_list property of each user, which requires an extra nested loop:
let refList = Database.database().reference().child("Users/Sellers")
refList.observe(DataEventType.value, with:{(snapshot) in
if snapshot.childrenCount>0{
self.listProduct.removeAll()
for user in snapshot.children.allObjects as! [DataSnapshot]{
let productList = user.childSnapshot(forPath: "product_list")
for product in productList.children.allObjects as! [DataSnapshot]{
let userList = product.value as? [String: AnyObject]
let listName = userList?["name"]
let listDetail = userList?["details"] // NOTE: also fixed a typo here
let listPrice = userList?["price"]
print("key = \(listName)")
let list = ListModel(name: listName as! String?, detail: listDetail as! String?, price: listPrice as! String?)
self.listProduct.append(list)
}
}
self.tableList.reloadData()
}
})

Related

Sorting cells instead of table

My App checks which POI/ Feed/ Group the user is following. Based on that it loads comments with the content of the comment and the user name/picture. Those are loaded separately. My only issue is sorting by time.
If I use this code: self.table = self.table.sorted(by: { $0.userTime ?? 0 > $1.userTime ?? 0 }) the sorting of the comments is correct. But the matching of the profile names and pictures is totally wrong.
If I remove that code above the matching is correct but the sorting is totally wrong. How can I solve this? Instead of sorting the table I have to sort the cell itself?
func loadFollowedPoi() {
myFeed.myArray1 = []
let userID = Auth.auth().currentUser!.uid
let database = Database.database().reference()
database.child("user/\(userID)/abonniertePoi/").observeSingleEvent(of: .value, with: { snapshot in
for child in snapshot.children.allObjects as! [DataSnapshot] {
myFeed.myArray1.append(child.key)
}
self.postsLaden()
})
}
func postsLaden() {
dic = [:]
let neueArray: [String] = []
for groupId in myFeed.myArray1[0..<myFeed.myArray1.count] {
let placeIdFromSearch = ViewController.placeidUebertragen
ref = Database.database().reference().child("placeID/\(groupId)")
ref.observe(DataEventType.childAdded, with: { snapshot in
guard let dic = snapshot.value as? [String: Any] else { return }
let newPost = importPosts(dictionary: dic, key: snapshot.key)
guard let userUid = newPost.userID else { return }
self.fetchUser(uid: userUid, completed: {
self.table.insert(newPost, at: 0)
self.table = self.table.sorted(by: { $0.userTime ?? 0 > $1.userTime ?? 0 })
self.tableView.reloadData()
})
}
)}
}
func fetchUser(uid: String, completed: #escaping () -> Void) {
ref = Database.database().reference().child("user").child(uid).child("userInformation")
ref.observe(.value) { (snapshot) in
guard let dic = snapshot.value as? [String: Any] else { return }
let newUser = UserModel(dictionary: dic)
self.users.insert(newUser, at: 0)
completed()
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
cell.layoutMargins = UIEdgeInsets.zero
cell.post = table[indexPath.row]
cell.user = users[indexPath.row]
return cell
}
class importPosts {
var userID: String?
var userGroup: String?
var userComment: String?
var userTime: Int?
var userLikes: Int?
var commentId: String?
var placeID: String?
var kommentarCount: Int?
var id: String?
var likeCount: Int?
var likes: Dictionary<String, Any>?
var isLiked: Bool?
init(dictionary: [String: Any], key: String) {
userID = dictionary["userID"] as? String
userComment = dictionary["userComment"] as? String
userGroup = dictionary["userGroup"] as? String
userTime = dictionary["userTime"] as? Int
userLikes = dictionary["userLikes"] as? Int
commentId = dictionary["commentId"] as? String
placeID = dictionary["placeID"] as? String
kommentarCount = dictionary["kommentarCount"] as? Int
id = key
likeCount = dictionary["likeCount"] as? Int
likes = dictionary["likes"] as? Dictionary<String, Any>
ViewComments.commentIDNew = commentId!
if let currentUserUid = Auth.auth().currentUser?.uid {
if let likes = self.likes {
isLiked = likes[currentUserUid] != nil
}
}
}
}
As suggested in the comments create a parent struct which contains one user an one post respectively
struct UserData {
let user: UserModel
let post: importPosts
}
Side note: Please name structs/classes always uppercase and why not simply User and Post?
Create the datasource array
var users = [UserData]()
Modify fetchUser to pass the new user in the completion handler
func fetchUser(uid: String, completed: #escaping (UserModel) -> Void) {
ref = Database.database().reference().child("user").child(uid).child("userInformation")
ref.observe(.value) { (snapshot) in
guard let dic = snapshot.value as? [String: Any] else { return }
let newUser = UserModel(dictionary: dic)
completed(newUser)
}
}
And modify also postsLaden to assign the post and the associated user to the model
func postsLaden() {
//dic = [:]
//let neueArray: [String] = [] seems to be unused
for groupId in myFeed.myArray1[0..<myFeed.myArray1.count] {
let placeIdFromSearch = ViewController.placeidUebertragen
ref = Database.database().reference().child("placeID/\(groupId)")
ref.observe(DataEventType.childAdded, with: { snapshot in
guard let dic = snapshot.value as? [String: Any] else { return }
let newPost = importPosts(dictionary: dic, key: snapshot.key)
guard let userUid = newPost.userID else { return }
self.fetchUser(uid: userUid, completed: { user in
self.users.insert(UserData(user: user, post: newPost), at: 0)
self.users.sort($0.user.userTime ?? 0 > $1.user.userTime ?? 0)
self.tableView.reloadData()
})
}
)}
}
Finally modify cellForRow
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
cell.layoutMargins = UIEdgeInsets.zero
let user = users[indexPath.row]
cell.post = user.post
cell.user = user.user
return cell
}
Yet another side note: Sorting and reloading the table view multiple times inside the loop is unnecessarily expensive. You could add DispatchGroup to sort and reload the data once on completion. Regarding expensive: In the database isn't it possible that Post can hold a full reference to the user to avoid the second fetch? For example Core Data can.

Reloading tableView after liking a button in cell

My tableView shows some user comments loaded via Firebase Database. The tableView contains also a prototype cell. First of all loadPosts() gets executed. It loads every post and also goes to the user and takes the profile picture which is up to date and at last it sorts them after time.
Now the user has the option to like a post. In the extension UITableViewDelegate I created a cell.buttonAction. Here it opens into the users account and looks if he already liked the post with a specific id. If not it adds +1. If it did already it takes one -1.
The code itself works. But I have huge performance issues. Sometime the tableView gets updated immidiately. Sometimes I have to manually refresh it. As you can see right now I use observeSingleEvent. Should I better use observe instead? But then it crashes sometimes if someone posts and I have the same tableView opened. I also don't want it to reload every time the whole tableView if someone liked a post.
I also created a Video. Maybe it helps. I really do not know how I can solve that problem.
func loadPosts() {
let placeIdFromSearch = ViewController.placeidUebertragen
ref = Database.database().reference().child("placeID/\(placeIdFromSearch)")
ref.queryOrdered(byChild: "userTime").queryLimited(toLast: 10).observeSingleEvent(of: DataEventType.value, with: {(snapshot) in
self.table.removeAll()
for video in snapshot.children.allObjects as! [DataSnapshot] {
let Object = video.value as? [String: AnyObject]
let timestampDate = NSDate(timeIntervalSince1970: Double(Object?["userTime"] as! NSNumber)/1000)
...
let time = dateFormatter.string(from: timestampDate as Date)
...
let userTimeForArranging = Object?["userTime"]
ViewComments.commentIDNew = commentId as! String
getProfilePicture()
func getProfilePicture(){
self.ref = Database.database().reference()
self.ref.child("user/\(userID!)").observe (.value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
let userImage = value?["picture"] as? String ?? ""
let userName = value?["firstname"] as? String ?? ""
let video = importComment(userName: userName as! String, userGroup: userGroup as! String, userComment: userComment as! String, userTime: userTime as! String, userLikes: userLikes as! Int, commentId: commentId as! String, placeID: placeID as! String, kommentarCount: kommentarCount as! Int, userImage: userImage as! String, userTimeForArranging: userTimeForArranging as! Int)
self.table.insert(video, at: 0)
self.table = self.table.sorted(by: { $0.userTimeForArranging! > $1.userTimeForArranging! })
self.tableView.reloadData()
})
}
}
})
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableViewCell
let video: importComment
video = table[indexPath.row]
cell.layoutMargins = UIEdgeInsets.zero
...
cell.userImage.image = UIImage(url: URL(string: video.userImage!))
cell.buttonAction = {
getClickedRow(arg: true, completion: { (success) -> Void in
if success {
self.loadPosts()
} else {
}
})
func getClickedRow(arg: Bool, completion: #escaping (Bool) -> ()) {
let selectedIndexPath = self.table[indexPath.row].commentId!
ViewSubComments.subCommentIdNew = selectedIndexPath
completion(arg)
}
}
return cell
}
From Prototype cell:
#IBAction func buttonTapped(_ sender: UIButton) {
buttonAction?()
let ref = Database.database().reference()
let userID = Auth.auth().currentUser!.uid
ref.child("user/\(userID)/places/\(ViewController.placeidUebertragen)/\(ViewComments.commentIDNew)").observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.exists(){
getLikeAndMinusOne ()
let database = Database.database().reference()
database.child("user/\(userID)/places/\(ViewController.placeidUebertragen)/\(ViewComments.commentIDNew)").removeValue()
}else{
getLikeAndAddOne ()
let database = Database.database().reference()
let object: [String: Any] = [
"like": "true",]
database.child("user/\(userID)/places/\(ViewController.placeidUebertragen)/\(ViewComments.commentIDNew)").setValue(object)
}
})
func getLikeAndAddOne () {
let database = Database.database().reference()
database.child("placeID/\(ViewController.placeidUebertragen)/\(ViewComments.commentIDNew)").observeSingleEvent(of: .value, with: { (snapshot) in
let userDict = snapshot.value as! [String: Any]
let userLikes = userDict["userLikes"] as! Int
var userLikesNeu = Int(userLikes)
userLikesNeu = Int(userLikes) + 1
database.child("placeID/\(ViewController.placeidUebertragen)/\(ViewComments.commentIDNew)").updateChildValues(["userLikes": userLikesNeu])
})}
func getLikeAndMinusOne () {
let database = Database.database().reference()
database.child("placeID/\(ViewController.placeidUebertragen)/\(ViewComments.commentIDNew)").observeSingleEvent(of: .value, with: { (snapshot) in
let userDict = snapshot.value as! [String: Any]
let userLikes = userDict["userLikes"] as! Int
var userLikesNeu = Int(userLikes)
userLikesNeu = Int(userLikes) - 1
database.child("placeID/\(ViewController.placeidUebertragen)/\(ViewComments.commentIDNew)").updateChildValues(["userLikes": userLikesNeu])
})}
}

Showing post data from logged in user only swift/xcode/firebase

Hey I have been following tutorials online to try and make a social media app and it works fine where all the posts made by users populates in one scene but in another scene I would like for the users who are currently logged in to be able to see their posts only instead of having to find their posts from a bunch of posts made by other users, below are my code samples:
Posts Code:
import Foundation
import UIKit
import Firebase
class Posts{
var id: String
var author: UserProfile
var text: String
var timestamp:Double
var createdAt:Date
init(id:String, author:UserProfile,text:String,timestamp:Double) {
self.id = id
self.author = author
self.text = text
self.timestamp = timestamp
self.createdAt = Date(timeIntervalSince1970: timestamp / 1000)
}
static func parse(_ key:String, _ data:[String:Any]) -> Posts? {
if let author = data["author"] as? [String:Any],
let uid = author["uid"] as? String,
let name = author["name"] as? String,
let photoURL = author["photoURL"] as? String,
let url = URL(string:photoURL),
let text = data["text"] as? String,
let timestamp = data["timestamp"] as? Double {
let userProfile = UserProfile(uid: uid, name: name, photoURL: url)
return Posts(id: key, author: userProfile, text: text, timestamp:timestamp)
func performDeepQuery() {
guard let user = Auth.auth().currentUser else { return }
let uid = user.uid
let ref = Database.database().reference().child("posts")
let query = ref.queryOrdered(byChild: "author/uid").queryEqual(toValue: uid)
query.observeSingleEvent(of: .value, with: { snapshot in
let allPosts = snapshot.children.allObjects as! [DataSnapshot]
for postSnap in allPosts {
let text = postSnap.childSnapshot(forPath: "text").value as? String ?? "No Text"
print(text)
//same as above
}
})
}
}
return nil }
}
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0:
return theposts.count
case 1:
return fetchingMore ? 1 : 0
default:
return 0
} }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 { let cell = HomeViewControllerScene.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! Posting_TableViewCell
cell.set(theposts: theposts[indexPath.row])
return cell}
else {
let cell = HomeViewControllerScene.dequeueReusableCell(withIdentifier: "loadingCell", for: indexPath) as! LoadingCell
cell.spinner.startAnimating()
return cell
}
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cellHeights[indexPath] = cell.frame.size.height
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return cellHeights[indexPath] ?? 72.0
}
Please someone help me out here I have been scratching my head for a while with this!!!
I believe the question is how to get the posts for a certain user. The structure looks good but no need to have a child node 'author' in each post so instead of this:
posts
post_id_0
author
author data
text: "Hello, World"
uid: "uid_0"
do this
posts
post_id_0
text: "Hello, World"
uid: "uid_0"
name: "usmaan"
photoURL:"https://firebasestorage..."
So now just query for this users posts (this is for Firestore, scroll down fo the RTDB solution)...
func getThisUsersPosts() {
let uid = "uid_0" //this users uid
self.db.collection("posts]").whereField("uid", isEqualTo: uid).getDocuments { (snapshot, error) in
if let err = error {
print(err.localizedDescription)
return
}
if let doc = snapshot?.documents {
for d in doc {
let text = d.get("text") as? String ?? "No Post Text"
print(text)
}
} else {
print("no posts found")
}
}
}
self.db points to my Firestore.
EDIT:
OP is using the Real Time Database so here's the code for that
func getThisUsersPosts() {
let uid = "uid_0"
let ref = self.ref.child("posts") //self.ref points to MY firebase.
let query = ref.queryOrdered(byChild: "uid").queryEqual(toValue: uid)
query.observeSingleEvent(of: .value, with: { snapshot in
let allPosts = snapshot.children.allObjects as! [DataSnapshot]
for postSnap in allPosts {
let text = postSnap.childSnapshot(forPath: "text").value as? String ?? "No Text"
print(text)
}
})
}
EDIT 2:
OP wants to keep their same structure.
To query for data that's two levels deep we use what's called Deep Query and will look something like this:
func performDeepQuery() {
let uid = "uid_0"
let ref = self.ref.child("posts")
let query = ref.queryOrdered(byChild: "author/uid").queryEqual(toValue: uid)
query.observeSingleEvent(of: .value, with: { snapshot in
let allPosts = snapshot.children.allObjects as! [DataSnapshot]
for postSnap in allPosts {
//populate your tableView datasource here
let post = PostClass()
post.postId = postSnap.key
post.name = postStap.childSnapshot("name").value as? String ?? "No Post Name"
post.text = postStap.childSnapshot("text").value as? String ?? "No Post Text"
self.postArray.append(post)
}
self.myTableView.reloadData()
})
}
which will perform a deep query on this structure
posts
post_0
author
uid: "uid_0"
name: "post 0 name"
text: "post 0 text"
The PostClass could be this
class PostClass {
var postId = ""
var name = ""
var text = ""
}
More Info:
To get the current users uid (which is covered in the getting started guide as well) and assuming you are authenticated (otherwise it will be nil)
guard let user = Auth.auth().currentUser else { return }
let uid = user.uid

UISearchBar and Firebase Database

struct postStruct {
let title : String!
let author : String!
let bookRefCode : String!
let imageDownloadString : String!
let status : String!
let reserved : String!
let category : String!
let dueDate : String!
}
'Above is where i set up the structure for the post, and below, is how i reference and retrieve the data from the firebase database.
My problem is that when you set up the searcher, i do not know how to get it to search based off of the title of the post.'
class DirectoryTableView: UITableViewController {
var posts = [postStruct]()
override func viewDidLoad() {
let databaseRef = Database.database().reference()
databaseRef.child("Books").queryOrderedByKey().observe(.childAdded, with: {
snapshot in
var snapshotValue = snapshot.value as? NSDictionary
let title = snapshotValue!["title"] as? String
snapshotValue = snapshot.value as? NSDictionary
let author = snapshotValue!["author"] as? String
snapshotValue = snapshot.value as? NSDictionary
let bookRefCode = snapshotValue!["bookRefCode"] as? String
snapshotValue = snapshot.value as? NSDictionary
let status = snapshotValue!["status"] as? String
snapshotValue = snapshot.value as? NSDictionary
let reserved = snapshotValue!["reserved"] as? String
snapshotValue = snapshot.value as? NSDictionary
let category = snapshotValue!["category"] as? String
snapshotValue = snapshot.value as? NSDictionary
let dueDate = snapshotValue!["dueDate"] as? String
snapshotValue = snapshot.value as? NSDictionary
self.posts.insert(postStruct(title: title, author: author, bookRefCode: bookRefCode, status: status, reserved: reserved, category: category, dueDate: dueDate) , at: 0)
self.tableView.reloadData()
})
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return posts.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell")
let databaseRef = Database.database().reference()
let label1 = cell?.viewWithTag(1) as! UILabel
label1.text = posts[indexPath.row].title
let label2 = cell?.viewWithTag(2) as! UILabel
label2.text = posts[indexPath.row].author
let label3 = cell?.viewWithTag(3) as! UILabel
label3.text = posts[indexPath.row].bookRefCode
let label4 = cell?.viewWithTag(4) as! UILabel
label4.text = posts[indexPath.row].status
let label5 = cell?.viewWithTag(5) as! UILabel
label5.text = posts[indexPath.row].category
let image1 = cell?.viewWithTag(6) as! UILabel
image1.text = posts[indexPath.row].imageDownloadString
let label6 = cell?.viewWithTag(7) as! UILabel
label6.text = posts[indexPath.row].reserved
let label9 = cell?.viewWithTag(9) as! UILabel
label9.text = posts[indexPath.row].dueDate
return cell!
}
'Also, does anyone know how to sort the tableview cells (posts in this case) alphabetically?'
You can get all data already ordered alphabetically
databaseRef.child("Books").queryOrdered(byChild: "title").observe(.childAdded, with: { snapshot in
var snapshotValue = snapshot.value as? NSDictionary
let title = snapshotValue!["title"] as? String
snapshotValue = snapshot.value as? NSDictionary
....
}
or sort your array before reload the tableView
var sortedArray = swiftArray.sorted { $0.title.localizedCaseInsensitiveCompare($1.title) == ComparisonResult.orderedAscending }
Sample structure
for sorting data according to searchBar I had used an dictionary that having all my snapshot and I compared my searchBar text in that dict and after sorting reloaded tableView here is code that you can have a look at
//method to get all user Details in a dict
func getEmail() {
let databaseRef = Database.database().reference().child("users")
databaseRef.observe(.value, with: { (snapshot) in
if snapshot.exists(){
self.postData = snapshot.value as! [String : AnyObject]
let dictValues = [AnyObject](self.postData.values)
self.sarchDict = dictValues
}
})
}
//search bar delegate
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
if self.mySearchBar.text!.isEmpty {
// set searching false
self.isSearching = false
}else{
// set searghing true
self.isSearching = true
self.names.removeAll()
self.uidArray.removeAll()
self.imageUrl.removeAll()
for key in self.sarchDict {
let mainKey = key
//I am making query against email in snapshot dict
let str = key["email"] as? String
//taking value of email from my dict lowerCased to make query as case insensitive
let lowercaseString = str?.lowercased()
//checking do my any email have entered letter or not
if(lowercaseString?.hasPrefix(self.mySearchBar.text!.lowercased()))!{
//here I have a check so to remove value of current logged user
if ((key["uID"] as! String) != (Auth.auth().currentUser?.uid)!){
//If value is found append it in some arrays
self.imageUrl.append( key["profilePic"] as! String )
self.names.append( key["name"] as! String )
self.uidArray.append( key["uID"] as! String )
//you can check which values are being added from which key
print(mainKey)
}
}
}
//reload TableView here
}
}
//TableView
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
cell = self.myTableView.dequeueReusableCell(withIdentifier: "Cell")!
if self.isSearching == true {
let imageView = (cell.viewWithTag(1) as! UIImageView)
imageView.setRounded()
if imageUrl[indexPath.row] != "" {
self.lazyImage.showWithSpinner(imageView:imageView, url:imageUrl[indexPath.row])
}
else{
imageView.image = UIImage(named: "anonymous")
}
(cell.contentView.viewWithTag(2) as! UILabel).text = self.names[indexPath.row]
}
else {
}
return cell
}
I'm sure this will be helpful to some using FireStore. Here I'm just setting my reference to point to the right collection. "name" is my field I wish to search by and is greater than will be checked chronologically on my string. The further they type the more defined the search results are.
static func searchForProgramStartingWith(string: String) {
let programsRef = db.collection("programs")
programsRef.whereField("name", isGreaterThan: string).limit(to: 10).getDocuments { (snapshot, error) in
if error != nil {
print("there was an error")
} else {
let shots = snapshot?.documents
for each in shots! {
let data = each.data()
let name = data["name"]
print("The name is \(name!)")
}
}
}
}

populate tableview based on returned queryEqual(toValue)

I am having trouble populating a tableView based on snapshot keys. The console is printing all (nodeToReturn) values from the parent node and children that are called from the queryEqual(toValue: locationString), so I know I am querying them correctly. But for some reason my tableView keeps populating all the User dictionaries from my Database.database().reference().child("Travel_Experience_Places"). I just want the tableView to display the snapshot data from the "nodeToReturn" values, so not every parent node from my "Travel_Experience_Places" database reference - only the parent nodes that have the same value of "locationString" in its children. Hopefully that makes sense. Thanks in advance!
// model object
class User: SafeUserObject {
var id: String?
var name: String?
var email: String?
var profileImageUrl: String?
var place: String?
init(dictionary: [String: AnyObject]) {
super.init()
self.id = dictionary["fromId"] as? String
self.name = dictionary["addedBy"] as? String
self.email = dictionary["email"] as? String
self.profileImageUrl = dictionary["profileImageUrl"] as? String
self.place = dictionary["place"] as? String
setValuesForKeys(dictionary)
}
}
// JSON structure
"Travel_Experience_Places" : {
"-Ks0Ms4fEQZxBytI-vu_" : {
"addedBy" : "Daniel Meier",
"place" : "Barcelona, Spain",
"profileImageUrl" : "https://firebasestorage.googleapis.com/v0/b/travelapp-255da.appspot.com/o/profile_images%2F21673E85-4F58-480D-B0A9-65884CADF7B3.png?alt=media&token=9e111014-d1d7-4b3b-a8c2-3897032c34cc",
"timestamp" : 1.503261589872372E9
},
// tableview to return firebase queryEqual(toValue: locationString) in tableview
var experiencePlaceUsers = [User]()
func fetchTravelingUserCell() {
let databaseRef = Database.database().reference().child("Travel_Experience_Places")
databaseRef.queryOrdered(byChild: "place").queryEqual(toValue: locationString).observe(.value, with: { snapshot in
if snapshot.exists(){
let allKeys = snapshot.value as! [String : AnyObject]
let nodeToReturn = allKeys.keys
print(nodeToReturn) // prints parent and child values that have locationString as a child value in its data structure
}
})
databaseRef.observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User(dictionary: dictionary)
self.experiencePlaceUsers.append(user)
self.tableView.reloadData()
}
}, withCancel: nil)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return experiencePlaceUsers.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! UserCell
cell.user = experiencePlaceUsers[indexPath.item]
return cell
}
I believe you need to reload the tableview in your block where you get nodeToReurn
var experiencePlaceUsers = [User]()
func fetchTravelingUserCell() {
let databaseRef = Database.database().reference().child("Travel_Experience_Places")
databaseRef.queryOrdered(byChild: "place").queryEqual(toValue: locationString).observe(. childAdded, with: { snapshot in
if snapshot.exists(){
if let allKeys = snapshot.value as? [String: AnyObject] {
let singleUser = User(dictionary: allKeys)
self.experiencePlaceUsers.append(singleUser)
DispatchQueue.main.async(execute: {
self.tableView.reloadData()
})
}
}
})
/*
databaseRef.observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User(dictionary: dictionary)
self.experiencePlaceUsers.append(user)
self.tableView.reloadData()
}
}, withCancel: nil)
*/
}