Firebase - Swift - Delete a child UID from a snapshot - swift

I am trying to delete up the studentUser UID from my staffUsers. The UID I want to delete is nested in the staffUsers -> studentSession1List.
I have the UID listed with A Bool of True on creation. This "studentSession1List" will have lots of studentUsers in the list. I only want the studentUser that is logged in to have their UID(55FDLm9n6LccZBB7skaCbvfSHRz1) removed from the list.
let dataref = Database.database().reference()
dataref.child("staffUsers").queryOrdered(byChild: "studentSession1List").observe(.value, with: { (snapshot) in
for snap in snapshot.children {
guard let studentUID = Auth.auth().currentUser?.uid else { return }
let snapDataSnapshot = snap as! DataSnapshot
var snapValues = snapDataSnapshot.value as? [String: AnyObject]
if var snapWithReg = snapValues?["studentSession1List"] as? [String: Bool] {
print("This is the staff member")
print(snapWithReg)
print(snapWithReg.count)
snapWithReg.removeValue(forKey: studentUID)
}
}
}) { (error) in
print(error.localizedDescription)
}
Here is the output:
Full Function for Deleting and Adding the Student
func didSelect(for cell: StudentSearchCell) {
guard let indexpath = collectionView?.indexPath(for: cell) else { return }
let staffUser = self.users[indexpath.item]
let selectedUserId = staffUser.uid
guard let studentUID = Auth.auth().currentUser?.uid else { return }
let dataRef = Database.database().reference()
dataRef.child("staffUsers").queryOrdered(byChild: "studentSession1List").observe(.value, with: { (snapshot) in
for snap in snapshot.children {
guard let studentUID = Auth.auth().currentUser?.uid else { return }
let snapDataSnapshot = snap as! DataSnapshot
var snapValues = snapDataSnapshot.value as? [String: AnyObject]
if (snapValues? ["studentSession1List"] as? [String: Bool]) != nil {
dataRef.child("staffUsers").child(snapDataSnapshot.key).child("studentSession1List").child(studentUID).removeValue(completionBlock: { (error, ref) in
if error != nil {
print("Error: \(String(describing: error))")
return
}
print("Removed successfully")
})
}
}
}) { (error) in
print(error.localizedDescription)
}
// Add student to staff list
let ref = Database.database().reference().child("staffUsers").child(selectedUserId).child("studentSession1List")
let values = [studentUID: true]
ref.updateChildValues(values) { (err, ref) in
if let err = err {
print("Failed to follow user:", err)
return
}
}
// Add selected staff to student list
let studentRef = Database.database().reference().child("studentUsers").child(studentUID).child("studentSession1List")
studentRef.removeValue()
let studentValues = [selectedUserId: true]
studentRef.updateChildValues(studentValues) { (err, studentRef) in
if let err = err {
print("Failed to follow user:", err)
return
}
}
self.navigationController?.popViewController(animated: true)
}

I think you need to reach the child that you want to remove using the following code and then remove it.
Edit1:
Since inside staffUsers we have keys inside which studentSession1List is present inside which the value (studentUID) is present that we want to remove, so inside your already written code I have added the new code, please check
let dataref = Database.database().reference()
dataref.child("staffUsers").queryOrdered(byChild: "studentSession1List").observe(.value, with: { (snapshot) in
for snap in snapshot.children {
guard let studentUID = Auth.auth().currentUser?.uid else { return }
let snapDataSnapshot = snap as! DataSnapshot
var snapValues = snapDataSnapshot.value as? [String: AnyObject]
if var snapWithReg = snapValues?["studentSession1List"] as? [String: Bool] {
//Added code here
dataref.child("staffUsers").child(snapDataSnapshot.key).child("studentSession1List").child(studentUID).removeValue(completionBlock: { (error, ref) in
if error != nil {
print("Error: \(error)")
return
}
print("Removed successfully")
})
}
}
}) { (error) in
print(error.localizedDescription)
}
Edit2:
To delete the code once , we can use observeSingleEvent
observeSingleEvent(of: .value, with: { (snapshot) in
}, withCancel: nil)

Related

Pagination not working in Swift with Firebase

I am trying to paginate my data pull. But somehow it is not working and I am not sure what I am doing wrong.
In my viewDidLoad I call this function:
var currentKey: String?
func fetchNotifications() {
guard let currentUid = Auth.auth().currentUser?.uid else { return }
if currentKey == nil {
//initial data pull
NOTIFICATIONS_REF.child(currentUid).queryLimited(toLast: 16).observeSingleEvent(of: .value) { (snapshot) in
guard let first = snapshot.children.allObjects.first as? DataSnapshot else { return }
guard let allObjects = snapshot.children.allObjects as? [DataSnapshot] else { return }
allObjects.forEach({ (snapshot) in
let notificationId = snapshot.key
guard let dictionary = snapshot.value as? Dictionary<String, AnyObject> else { return }
guard let uid = dictionary["uid"] as? String else { return }
Database.fetchUser(with: uid, completion: { (user) in
// if notification is for post
if let postId = dictionary["postId"] as? String {
Database.fetchPost(with: postId, completion: { (post) in
let notification = Notification(user: user, post: post, dictionary: dictionary)
if notification.notificationType == .Comment {
self.getCommentData(forNotification: notification)
}
self.notifications.append(notification)
self.notifications.sort { (notification1, notification2) in
return notification1.creationDate > notification2.creationDate
}
self.tableView.reloadData()
})
} else {
let notification = Notification(user: user, dictionary: dictionary)
self.notifications.append(notification)
self.notifications.sort { (notification1, notification2) in
return notification1.creationDate > notification2.creationDate
}
self.tableView.reloadData()
self.tableView.refreshControl?.endRefreshing()
}
})
})
self.tableView.refreshControl?.endRefreshing()
}
} else {
NOTIFICATIONS_REF.child(currentUid).queryOrderedByKey().queryEnding(atValue: self.currentKey).queryLimited(toLast: 3).observeSingleEvent(of: .value) { (snapshot) in
guard let first = snapshot.children.allObjects.first as? DataSnapshot else { return }
guard let allObjects = snapshot.children.allObjects as? [DataSnapshot] else { return }
allObjects.forEach({ (snapshot) in
let notificationId = snapshot.key
guard let dictionary = snapshot.value as? Dictionary<String, AnyObject> else { return }
guard let uid = dictionary["uid"] as? String else { return }
Database.fetchUser(with: uid, completion: { (user) in
if notificationId != self.currentKey {
// if notification is for post
if let postId = dictionary["postId"] as? String {
Database.fetchPost(with: postId, completion: { (post) in
let notification = Notification(user: user, post: post, dictionary: dictionary)
if notification.notificationType == .Comment {
self.getCommentData(forNotification: notification)
}
self.notifications.append(notification)
self.notifications.sort { (notification1, notification2) in
return notification1.creationDate > notification2.creationDate
}
self.tableView.reloadData()
})
} else {
let notification = Notification(user: user, dictionary: dictionary)
self.notifications.append(notification)
self.notifications.sort { (notification1, notification2) in
return notification1.creationDate > notification2.creationDate
}
self.tableView.reloadData()
self.tableView.refreshControl?.endRefreshing()
}
}
})
})
}
}
}
I am populating the currentKey so it is no longer nil. The idea is that the else-statement then comes into place. But the else-statement is not being called .. I was also printing the currentKey after the initial data pull, so I know it is being populated, but still the else does not come into action.

In firebase chat how to update receiver user on chat message send in swift

I am try to make firebase chat message sent but not update on the other user.
But the message update on the firebase data base.
my Code is :-
guard let myid = “Xyz”
database.child(ChatDataBase.messages).child("\(conversation)").observeSingleEvent(of: .value) { [weak self] snapshot in
guard let strongSelf = self else {
return
}
let messageDate = newMessage.sentDate
let dateString = ChatViewController.dateFormatters.string(from: messageDate)
var message = “text”
let newMessageEntry: [String: Any] = [
"id": newMessage.messageId,
ChatConstant.content: message,
ChatConstant.sender_id: myid,
ChatConstant.reciever_id: otherUserId,
]
guard let keys = self?.database.childByAutoId().key else {
completion(.failure(DatabaseError.failedToFetch))
return
}
let messageDB = Database.database().reference().child(ChatDataBase.messages).child(conversation)
let userMessages = messageDB.queryOrdered(byChild: ChatConstant.reciever_id).queryEqual(toValue: otherUserId)
strongSelf.database.child(ChatDataBase.messages).child("\(conversation)").child(keys).setValue(newMessageEntry) { (error, ref) in
guard error == nil else {
completion(.failure(DatabaseError.failedToFetch))
return
},userMessages.observe(.childAdded) { (snapshot) in
if let conversations_value = snapshot.value as? [String: Any] {
}
} withCancel:nil}
completion(.success(newMessageEntry))}
}}

Swift - Remove key and values from dictionary [String : Any]

I am trying to removed block users from a dictionary [String : Any] that I am grabbing from the database. At first I grab the list of UID's that the current user has blocked:
var updatedBlockList: Any?
func findBlockUsers() {
// find current users list of blocked users
guard let currentUserUid = Auth.auth().currentUser?.uid else { return }
let blockedUsers = Database.database().reference().child("users").child(currentUserUid)
blockedUsers.observeSingleEvent(of: .value, with: { (snapshot) in
guard let userIdsDictionary = snapshot.value as? [String: Any] else { return }
userIdsDictionary.forEach({ (key, value) in
guard let userDictionary = value as? [String: Any] else { return }
var blockedList : Any
blockedList = userDictionary.keys
print(blockedList)
self.updateBlockList(blockedList: blockedList)
})
})
}
func updateBlockList(blockedList: Any) {
updatedBlockList = blockedList
print(updatedBlockList)
}
If I print updatedBlockList I get: ["gdqzOXPWaiaTn93YMJBEv51UUUn1", "RPwVj59w8pRFLf55VZ6LGX6G2ek2", "xmigo8CPzhNLlXN4oTHMpGo7f213"]
I now want to take those UID's (which will be the key in UserIdsDictionary and remove them after I pull ALL the users:
fileprivate func fetchAllUserIds() {
let ref = Database.database().reference().child("users")
ref.observeSingleEvent(of: .value, with: { (snapshot) in
guard let userIdsDictionary = snapshot.value as? [String: Any] else { return }
userIdsDictionary.forEach({ (key, value) in
// attempting to remove the blocked users here without any luck
var updatedKey = key as String?
updatedKey?.remove(at: self.updatedBlockList as! String.Index)
print(updatedKey!)
guard let userDictionary = value as? [String: Any] else { return }
let user = User(uid: key, dictionary: userDictionary)
self.fetchPostsWithUser(user: user)
})
}) { (err) in
print("Failed to fetch following user ids:", err)
}
}
I get this error when trying to remove: Could not cast value of type 'Swift.Dictionary.Keys' (0x1de2f6b78) to 'Swift.String.Index'
I'm sure i'm going about this the wrong way, but I know i'm close. The end goal is to take the blocked users UID's and remove them from the dictionary. Any help would be very much appreciated!!
Your forEach loop on userIdsDictionary is the wrong approach here so rather than trying to fix that code I would use a different approach and loop over the updatedBlockList
for item in updatedBlockList {
if let userID = item as? String {
userIdsDictionary.removeValue(forKey: userID)
}
}
For anyone wondering, here is the final changes that were made to make it work.
var updatedBlockList = [String]()
func findBlockUsers() {
// find current users list of blocked users
guard let currentUserUid = Auth.auth().currentUser?.uid else { return }
let blockedUsers = Database.database().reference().child("users").child(currentUserUid)
blockedUsers.observeSingleEvent(of: .value, with: { (snapshot) in
guard let userIdsDictionary = snapshot.value as? [String: Any] else { return }
userIdsDictionary.forEach({ (key, value) in
guard let userDictionary = value as? [String: Any] else { return }
let blockedList = Array(userDictionary.keys)
print(blockedList)
self.updateBlockList(blockedList: blockedList)
})
})
}
func updateBlockList(blockedList: [String]) {
updatedBlockList = blockedList
print(updatedBlockList)
}
fileprivate func fetchAllUserIds() {
let ref = Database.database().reference().child("users")
ref.observeSingleEvent(of: .value, with: { [weak self] (snapshot) in
guard var userIdsDictionary = snapshot.value as? [String: Any], let self = self else { return }
for item in self.updatedBlockList {
userIdsDictionary.removeValue(forKey: item)
}
userIdsDictionary.forEach({ (key, value) in
guard let userDictionary = value as? [String: Any] else { return }
let user = User(uid: key, dictionary: userDictionary)
self.fetchPostsWithUser(user: user)
})
}) { (err) in
print("Failed to fetch following user ids:", err)
}
}

Posts being loaded for all users in collection view firebase & swift

All I'm trying to do is fetch all the posts to the collection view that are within a certain radius of the current user. Currently I'm getting all the current users posts within the location but that is all. I can't figure out how to convert it to fetch all the posts from all the users.
FetchPostUserIds Is returning a snapshot of all the users and there UID
The geoFire query is only returning the postId from the current user. It shouldn't be I assume
Note: Updated Code
var PostKey: String?
var geoFire: GeoFire?
var regionQuery: GFRegionQuery?
var foundQuery: GFCircleQuery?
var geoFireRef: DatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
guard let uid = Auth.auth().currentUser?.uid else { return }
geoFireRef = Database.database().reference().child("posts").child(uid)
geoFire = GeoFire(firebaseRef: geoFireRef)
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLocation: CLLocation = locations[0] as CLLocation
let currentUserLocation = userLocation
let circleQuery = geoFire?.query(at: currentUserLocation, withRadius: 100.0)
_ = circleQuery?.observe(.keyEntered, with: { (key, location) in
self.PostKey = key
self.locationManager.stopUpdatingLocation()
})
}
fileprivate func fetchPostsWithUser(user: User) {
guard let key = PostKey else { return }
let ref = Database.database().reference().child("posts").child(user.uid).child(key)
ref.observeSingleEvent(of: .value, with: { (snapshot) in
self.collectionView?.refreshControl?.endRefreshing()
guard let dictionary = snapshot.value as? [String: Any] else { return }
var post = Post(user: user, dictionary: dictionary)
post.id = key
self.posts.append(post)
self.posts.sort(by: { (post1, post2) -> Bool in
return post1.creationDate.compare(post2.creationDate) == .orderedDescending
})
self.collectionView?.reloadData()
}) { (error) in
print(error)
}
}
fileprivate func fetchPostUserIds() {
let ref = Database.database().reference().child("users")
ref.observeSingleEvent(of: .value, with: { (snapshot) in
guard let userIdKey = snapshot.value as? [String: Any] else { return }
userIdKey.forEach({ (key, value) in
Database.fetchUserWithUID(uid: key, completion: { (user) in
self.fetchPostsWithUser(user: user)
})
})
}) { (error) in
print(error)
}
}
Try to debug and look what you got in the snapshot in your function, and also what fetchUserWithUID return
fileprivate func fetchPostUserIds() {
let ref = Database.database().reference().child("users")
ref.observeSingleEvent(of: .value, with: { (snapshot) in
guard let userIdKey = snapshot.value as? [String: Any] else { return }
userIdKey.forEach({ (key, value) in
Database.fetchUserWithUID(uid: key, completion: { (user) in
self.fetchPostsWithUser(user: user)
})
})
}) { (error) in
print(error)
}
}
Maybe with some more information I can help you
You pass paremeter user: User to method fetchPostsWithUser, but you always use the current user
guard let uid = Auth.auth().currentUser?.uid else { return }
also note these
let ref = Database.database().reference().child("users")
ref.observe(.value, with: { (snapshot) in
will load every change so think about singleObserve

Swift index out of range when refreshing

so ive been tring to solve this on my own for a few hours now. When ever i pull to refresh its crashes saying index out of range. Some people say its because of removing the arrays data before getting it and all that but only confused me further
here is my code
#objc fileprivate func fetchPostsWithUser() {
houses.removeAll()
myJobs.removeAll()
let ref = Database.database().reference().child("posts")
ref.observeSingleEvent(of: .value, with: { (snapshot) in
guard let dictionaries = snapshot.value as? [String: Any] else { return }
dictionaries.forEach({ (key, value) in
guard let dictionary = value as? [String: Any] else { return }
var post = Post(dictonary: dictionary)
post.id = key
Database.database().reference().child(key).observeSingleEvent(of: .value, with: { (snapshot) in
if post.pickedUserId == Auth.auth().currentUser?.uid {
self.myJobs.append(post)
} else if post.hasPicked == true && post.pickedUserId != Auth.auth().currentUser?.uid {
print("taken out")
} else {
self.houses.append(post)
}
self.houses.sort(by: { (p1, p2) -> Bool in
return p1.creationDate.compare(p2.creationDate) == .orderedDescending
})
self.tableView.reloadData()
}, withCancel: { (err) in
print("Failed to fetch like info for post:", err)
})
})
}) { (err) in
print("Failed to fetch posts:", err)
}
}
A solution to this error will be greatly appreciated, thank you.