I tried to set up a function to listen for changes within a certain part of my database:
private func observeParticipants() {
let databaseRef = FIRDatabase.database().reference()
let groupRef = databaseRef.child("groups").child(currentRoomID).child("participants")
groupRef.observe(.childAdded, with: { snapshot in
print("observe snapshot.value: \(snapshot.value)")
if let snapDict = snapshot.value as? [String:AnyObject] {
for each in snapDict {
let uid = each.key
let avatar = each.value["profilePicture"] as! String
let gender = each.value["gender"] as! String
let handle = each.value["handle"] as! String
let name = each.value["name"] as! String
let status = each.value["status"] as! String
// Set those to the dictionaries [UID : value]
self.avatarDictionary.setValue(avatar, forKey: uid)
self.nameDictionary.setValue(name, forKey: uid)
self.genderDictionary.setValue(gender, forKey: uid)
self.handleDictionary.setValue(handle, forKey: uid)
self.statusDictionary.setValue(status, forKey: uid)
print("\n\navatarDictionary:\n \(self.avatarDictionary)")
print("\nhandleDictionary:\n \(self.handleDictionary)")
print("\ngenderDictionary:\n \(self.genderDictionary)")
print("\nnameDictionary:\n \(self.nameDictionary)")
print("\nstatusDictionary:\n \(self.statusDictionary)")
self.navBarCollectionView.reloadData()
}
}
})
}
When I run this, it loads the correct values, but if I make a change, for example add a new user to the group, it doesn't reflect that change. The database is updated fine, but the observer isn't seeing that. Is there any way I can re-write this to make is observe properly? I can post my database structure if it will help.
Thanks!
EDIT: Database structure:
https://pastebin.com/SZ2mE2Vt
EDIT: snapshot.value after adding second user:
Snapshot.value: Optional({
gender = female;
handle = sav;
name = Savina;
profilePicture = "https://graph.facebook.com/1929991317219760/picture?type=large&return_ssl_resources=1";
status = F8B016;
})
EDIT 2:
This is the code that works for fetching all user values initially, and also every time I leave the view and come back. It just doesn't act properly as an observer, i.e. if I add a participant, it doesn't see that and update the necessary values such as the collection view. I have to leave the view and come back for that to happen.
func getParticipantInfo() {
let databaseRef = FIRDatabase.database().reference()
let groupRef = databaseRef.child("groups").child(currentRoomIdGlobal)
groupRef.observe(.childAdded, with: { snapshot in
if let snapDict = snapshot.value as? [String : AnyObject] {
for each in snapDict {
let uid = each.key
let avatar = each.value["profilePicture"] as! String
let gender = each.value["gender"] as! String
let handle = each.value["handle"] as! String
let name = each.value["name"] as! String
let status = each.value["status"] as! String
// Set those to the dictionaries [UID : value]
self.avatarDictionary.setValue(avatar, forKey: uid)
self.nameDictionary.setValue(name, forKey: uid)
self.genderDictionary.setValue(gender, forKey: uid)
self.handleDictionary.setValue(handle, forKey: uid)
self.statusDictionary.setValue(status, forKey: uid)
print("\n\navatarDictionary:\n \(self.avatarDictionary)")
print("\nhandleDictionary:\n \(self.handleDictionary)")
print("\ngenderDictionary:\n \(self.genderDictionary)")
print("\nnameDictionary:\n \(self.nameDictionary)")
print("\nstatusDictionary:\n \(self.statusDictionary)")
self.navBarCollectionView.reloadData()
}
}
})
}
Related
I'm working on a follow friends view controller that loads all the usernames in the database, BUT I don't want it to load the current user's username. I need to access the username from the currentUser's uid, and add all the usernames that are not equal to it to my array.
#objc func loadData() {
let rootRef = Database.database().reference()
let query = rootRef.child("users").queryOrdered(byChild: "username")
query.observeSingleEvent(of: .value) {
(snapshot) in
for child in snapshot.children.allObjects as! [DataSnapshot] {
let value = child.value as? NSDictionary
let username = value?["username"] as? String ?? ""
if username != rootRef.child(Auth.auth().currentUser!.uid).value(forKey: "username") as! String{
self.usernames.append(username)
}
print(username)
}
self.tableView.reloadData()
print(self.usernames)
}
}
You should try and minimise queries inside loops, especially irrelevent ones. Given your database schema uses the users unique id as the key, you can run your evaluation based on that key using child.key.
#objc func loadData() {
let rootRef = Database.database().reference()
let query = rootRef.child("users").queryOrdered(byChild: "username")
query.observeSingleEvent(of: .value) { (snapshot) in
for child in snapshot.children.allObjects as! [DataSnapshot] {
let value = child.value as? NSDictionary
let username = value?["username"] as? String ?? ""
if Auth.auth().currentUser!.uid != child.key {
self.usernames.append(username)
}
print(username)
}
self.tableView.reloadData()
print(self.usernames)
}
}
I fetch data and display in a tableView, the problem is the data is not executing in the correct order.
I have tried:
for case let child as DataSnapshot in data!.children.reversed() {
let newDispatchGroup = DispatchGroup()
let commentID = child.key
let uid = child.childSnapshot(forPath: "UID").value as! String
let commentText = child.childSnapshot(forPath: "Comment").value!
let timeStamp = child.childSnapshot(forPath: "timeStamp").value!
let date = ConvertDate(mediaTimestamp: timeStamp as! Double).getDate!
//print(date, "dsfsdafdasfdsafdsahjkfhfdsafsajkadhffdsfsafsasjkfhsdajkhfdsajkhfjklads")
newDispatchGroup.enter()
ref.child("users2").child(uid).observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot, "dshjkfhjkadhfsjkfhsdajkhfdsajkhfjklads")
print(date, "dsfsdafdasfdsafdsahjkfhfdsafsajkadhffdsfsafsasjkfhsdajkhfdsajkhfjklads")
let username = snapshot.childSnapshot(forPath: "username").value
let profileImage = snapshot.childSnapshot(forPath: "profileImage").value
let newUser = User(theuserID: uid, theUsername: username as! String, theprofImage: profileImage as! String)
let newComment = Comment(newUser: newUser, text: commentText as! String, timeStamp: date, NcommentID: commentID)
self.commentsVC1.arrayOfComments.append(newComment)
newDispatchGroup.leave()
//completion()
})
newDispatchGroup.notify(queue: .main, execute: {
print(self.totalComments, "COgfdsdfgfdsgdsfgdfsgfdsgdfsgdskj", self.commentsVC1.arrayOfComments.count)
if self.totalComments == self.commentsVC1.arrayOfComments.count {
print("COmejkfbdshkafdsagfhksdagfdsakj")
self.commentsVC1.tableView.reloadData()
}
})
}
})
}
But it did not work either, the order in which the second firebase calls execute is incorrect.
You should set up your notify closure when you set up your DispatchGroup. And you would not need to use a completion closure for you loadComments function.
let dispatchGroup = DispatchGroup()
dispatchGroup.notify(queue: .main, execute: {
if self.totalComments == self.commentsVC1.arrayOfComments.count {
print("COmejkfbdshkafdsagfhksdagfdsakj")
self.commentsVC1.tableView.reloadData()
}
})
loadComments()
notify will be called, when leave has been called the same amount of times as enter. In your code the last leave call is happening before you have set the anything to be notified about.
I solved with this:
for case let child as DataSnapshot in snap.children.reversed() {
let commentID = child.key
let uid = child.childSnapshot(forPath: "UID").value as! String
let commentText = child.childSnapshot(forPath: "Comment").value!
let timeStamp = child.childSnapshot(forPath: "timeStamp").value!
let date = ConvertDate(mediaTimestamp: timeStamp as! Double).getDate!
let newUser = User(theuserID: uid)
let newComment = Comment(newUser: newUser, text: commentText as! String, timeStamp: date, NcommentID: commentID)
self.commentsVC1.arrayOfComments.append(newComment)
ref.child("users2").child(uid).observeSingleEvent(of: .value, with: { (snapshot) in
let username = snapshot.childSnapshot(forPath: "username").value
let profileImage = snapshot.childSnapshot(forPath: "profileImage").value
let newUserIner = User(theuserID: uid, theUsername: username as! String, theprofImage: profileImage as! String)
newComment.user = newUserIner
if self.totalComments == self.commentsVC1.arrayOfComments.count {
self.commentsVC1.tableView.reloadData()
}
})
}
I would use dispatch group here though so one does not have have to check if its done unnecessarily.
I have this function that it will be triggered every time a user changes his picture, and will get the profilePictureUrl of the current user and update all posts matching the currentUser in the database. Works fine! Is doing the job. How do I update the indexPath of those particular cells? Right now my cells images are empty after the update.
var pathToPictures = [Pictures]()
func updateAllImagesOfCurrentUserInDatabase() {
//refrences
let ref = FIRDatabase.database().reference()
let uid = FIRAuth.auth()?.currentUser?.uid
//match the user ID value stored into posts with current userID and get all the posts of the user
let update = ref.child("posts").queryOrdered(byChild: "userID").queryEqual(toValue: uid)
update.observe(FIRDataEventType.value, with: { (snapshot) in
self.pathToPictures.removeAll()
if snapshot.value as? [String : AnyObject] != nil {
let results = snapshot.value as! [String : AnyObject]
for (_, value) in results {
let pathToPostPicture = Pictures()
if let pathToImage = value["pathToImage"] as? String , let postID = value["postID"] as? String {
pathToPostPicture.postImageUrl = pathToImage
pathToPostPicture.postID = postID
self.pathToPictures.append(pathToPostPicture)
print("Image and POST ID: \(pathToPostPicture.postImageUrl!)")
print("Post ID is : \(postID)")
if FIRAuth.auth()?.currentUser?.uid == uid {
ref.child("Users_Details").child(uid!).child("profileImageUrl").observeSingleEvent(of: .value, with: { (userSnapshot) in
print(userSnapshot)
let userIMageUrl = userSnapshot.value as! String
pathToPostPicture.postImageUrl = userIMageUrl
self.pathToPictures.append(pathToPostPicture)
print("This is the image path:" + userIMageUrl + String(self.pathToPictures.count))
// Update the Database
let postIDCount = pathToPostPicture.postID!
let updatedUserData = ["posts/\(postIDCount)/pathToImage": pathToPostPicture.postImageUrl!]
print("This is THE DATA:" , updatedUserData)
ref.updateChildValues(updatedUserData as Any as! [AnyHashable : Any])
})
}
print(self.pathToPictures.count)
}
}
} else {
print("snapshot is nill - add some data")
}
self.collectionView?.reloadData()
})
}
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 struggling with getting some of the data from my Firebase. This is how the structure looks like:
This is the code I retrieve the data with:
var followDatesDict = [String:String]()
databaseRef.child("FollowGroups").child(selectedFollowGroupId as String).observeSingleEvent(of: .value, with: { (snapshot) in
if snapshot.hasChildren(){
let name = snapshot.childSnapshot(forPath: "followgroupTitle").value as! String
let sDate = snapshot.childSnapshot(forPath: "startDate").value as! String
let eDate = snapshot.childSnapshot(forPath: "endDate").value as! String
followDatesDict = snapshot.childSnapshot(forPath: "followDates")......
}
})
I can retrieve name, sDate, and eDate just fine. But does anyone know how I can fill up the followDatesDict ordered by date? As you see in the structure of followDates, the key is a String of dates and a String value.
Thanks!
Ok, I managed to get the data. I also add them into a struct.
let enumerator = snapshot.childSnapshot(forPath: "followDates").children
while let rest = enumerator.nextObject() as? FIRDataSnapshot {
let key_followDate = rest.key
let value_UserId = rest.value as! String
//add to dictionary
self.followDatesDict.insert(followgroupOverview(followDate:key_followDate, followUserId:value_UserId), at: 0)
}