My JSON looks like this:
users
username1: "WWOdh96Yr3Qs4N3GWDVq3OlQFfB2"
username2: "RJ6PztTLmsg222oUygWHtWpVHdg1"
I would like to get "username1" by their key which is (auth.uid)! and if its found i want to delete it, So after delete it will be looks like this:
users
username2: "RJ6PztTLmsg222oUygWHtWpVHdg1"
.
self.ref.child("users").queryOrderedByValue().queryEqual(toValue: user?.uid).observe(.value, with: { snapshot in
if snapshot.exists() {
print("\(snapshot.value)")
snapshot.ref.child(snapshot.value as! String).removeValue() // this deleting every thing which is WRONG!
} else{
print("Not found--")
}
self.ref.removeAllObservers()
})
}
This code deleting everything in users. I just want to delete specific user.
First of all, my approach is if I want to query 1 value at 1 moment, like you are doing, I do a observeSingleEvent (is this the best approach?). But to solve your problem, you forgot to add your "users" path. Below code is more safe to use, since you force unwrap (which is not recommend for this case):
let dataRef = self.ref.child("users")
dataRef.keepSynced(true)
if let usersUID = Auth.auth().currentUser?.uid{
dataRef.child("users").queryOrderedByValue().queryEqual(toValue: usersUID).observeSingleEvent(.value, with: { snapshot in
print(snapshot)
let values = snapshot.value as? NSDictionary
for (key, value) in values{
print(value) // does this print the uid?
print(key) // or this one?
self.ref.child("users/\(key)").removeValueWithCompletionBlock({ (err, ref) in
if err != nil {
print(err)
} else {
print(ref)
print("Removed")
}
})
}
})
}
Try to add this, right after the print(snapshot)
Related
My datamodel looks as follows :
allcomments
|__$comment_id_5
|__post_id: <post_id_5>
uid
|
|__activity
|__comments
|__$random_activity_id
|__post_id : <post_id_5> //ref to post_id_5 in allcomments
|__comment_id : <comment_id_5> // ref to comment_id_5 in allcomments
My Goal: To check if the user with uid has commented on the post or not. If that person has, then I he can proceed further else he'll be shown something else on the screen. On trying the following query, I am able to only get the callback when a snapshot exists and not otherwise.
FBDataservice.ds.child("allcomments").queryOrdered(byChild: "post_id").queryEqual(toValue: "post_id_5").observeSingleEvent(of: .ChildAdded) { (snapshot) in
if let data = snapshot.value as? DataDict {
let comment = Comment(comId: snapshot.key , comData: data)
self.checkUserHasResponded(completion: { (hasResponded) in
if !hasResponded {
// Never returns it there is nothng
print("You gotta respond first")
} else {
//this part does work
print("Welcome to seeing everything")
}
})
}
}
func checkUserHasResponded(completion: #escaping (Bool) -> ()) {
FBDataservice.ds.REF_USERS.child(uid).child("activity/comments").queryOrdered(byChild: "post_id").queryEqual(toValue: "post_id_5").observeSingleEvent(of: .value) { (snapshot) in
snapshot.exists() ? completion(true) : completion(false)
}
}
I even tried tweaking the architecture this way and query it differently, still nothing work and the program behaves in the same exact way as incase of above.
uid
|
|__activity
|__comments
|__post_id_5 : comment_id_5
and ran this query:
func checkUserHasResponded(completion: #escaping (Bool) -> ()) {
FBDataservice.ds.REF_USERS.child(uid).child("activity/comments").observeSingleEvent(of: .value) { (snapshot) in
snapshot.hasChild("post_id_5") ? completion(true) : completion(false)
}
}
I tried changing .childAdded to .value. It gives the same exact result. Tried changing .observeSingleEvent(of:) to .observe() as well. But nothing helps. I am not sure what exactly is wrong. Check plenty of answers here, none helped. What exactly am I over looking. Thanks for the help.
Use .value instead of .childAdded, that way it the closure is called whether or not the snapshot exists, Just a quick test shows it works.
func checkUserHasResponded() {
let uid = "uid_0"
let commentsRef = dbRef.child(uid).child("activity").child("comments")
commentsRef.queryOrdered(byChild: "post_id")
.queryEqual(toValue: "post_5")
.observeSingleEvent(of: .value) { snapshot in
if snapshot.exists() {
print("post exists")
} else {
print("post not found")
}
}
}
If your structure does not contain a post_id child value that exists then the output is
post not found
So this answer applies to the updated question. The code in the closure will not run if the node you're querying for does not exist because the query is using .childAdded
FBDataservice.ds.child("allcomments").queryOrdered(byChild: "post_id")
.queryEqual(toValue: "post_id_5")
.observeSingleEvent(of: .childAdded) { (snapshot) in
If that's changed to .value, it returns and the code in the closure runs if the node exists. Keeping in mind that you'll want to use
snapshot.exists()
with that as it will be nil if it doesn't.
I'm currently trying to code a function who pass the user Data when user exists. When the username is in the database, the code is okay, but if there is no username recorded in the database I don't know how to have a return function.
I'm beginner, this is what I did:
func observeUserByUsername(username: String, completion: #escaping (Userm?) -> Void) {
REF_USERS.queryOrdered(byChild: "username_lowercase").queryEqual(toValue: username).observeSingleEvent(of: .childAdded) { (snapshot) in
if let dict = snapshot.value as? [String: Any] {
let user = Userm.transformUser(dict: dict, key: snapshot.key)
completion(user)
} else {
print("no user")
completion(nil)
}
}
}
I would like to have something like this: if there is user with this username -> return nil (for the completion).
Do you know how I could do this?
So if I got it right, you want to just check if a user with the username exists. You can just enter the path to firebase and use the exists() method to check if this subnode exists. I have a similar method, you can maybe change it to fit into your project.
func checkUsernameAvailability(completion: #escaping (_ available:Bool)->()){
guard let lowercasedText = usernameTextField.text?.lowercased() else {completion(false); return}
let ref = Database.database().reference().child("users").child("username").child(lowercasedText)
ref.observeSingleEvent(of: .value) { (snapshot) in
if snapshot.exists(){
completion(false)
return
}else{
completion(true)
}
}
}
Be careful, Firebase is not case-sensitive (that's why I always check and also store the lowercased version). If your subnode e.g. is 'UserName' and you search for the name 'username' it will tell you that there is already one with this name.
I'm using this function to check to see if a certain handle exists in my database. It works fine for the most part - if the handle exists, it updates the table view to display that user. However if there is no match for the handle entered, my alert view is not showing up.
// Search DB for matching handles
#IBAction func searchHandleButtonPressed(_ sender: Any) {
if let handleToSearch = handleSearchTextField.text?.lowercased() {
let databaseRef = FIRDatabase.database().reference()
databaseRef.child("users").queryOrdered(byChild: "lowercaseHandle").queryEqual(toValue: handleToSearch).observeSingleEvent(of: .value, with: { (snapshot) in
if let snapDict = snapshot.value as? [String:AnyObject] {
for each in snapDict{
let key = each.key
let handle = each.value["handle"] as! String
self.returnedHandles.removeAll()
self.returnedHandles.append(handle)
let pic = each.value["profilePicture"] as! String
self.returnedUsersProfilePic = pic
self.returnedUsersUID = key
if handle.lowercased() != handleToSearch {
self.noHandleFoundAlert()
}
if handle != "" {
DispatchQueue.main.async {
self.getFriendsInfo()
self.tableView.reloadData()
}
}
}
}
}, withCancel: {(Err) in
// print(Err.localizedDescription)
})
}
}
I put the alert in the loop as:
if handle.lowercased() != handleToSearch {
self.noHandleFoundAlert()
}
But obviously this isn't the correct approach as it isn't working. If I enter a random string of characters, or a handle that I know isn't in use, the alert doesn't come up. Where else would I put the alert so it will show up if there's no match?
The snapshot will be converted to an empty dictionary with your current code.
Before converting the snapshot.value to a Dictionary, check if it exists with snapshot.exists(): https://firebase.google.com/docs/reference/ios/firebasedatabase/api/reference/Classes/FIRDataSnapshot#-exists
You first have to check if the query you made, has data. So you have a
.hasChild("handle")
it returns a boolean, so when is true you do the loop, else notified user.
I'm having trouble updating a value in my Firebase database with the key status. I just can't figure out how to access the child(id) in which it is an autoID. Should I have an attribute in my Swift 3 Entity? Or is there a child(autoID) or something similar? I'm new in Firebase and Swift 3. Can any one help? This is my code:
self.ref?.child("requests").queryOrdered(byChild: "Sender").queryEqual(toValue: self.items[indexPath.row].Sender).setValue("2", forKey: "status"))
Swift 3 && Firebase 3
Hope this code will be help you...
// create the reference you want to observe
let myRequestRef = FIRDatabase.database().reference().child("requests").queryOrdered(byChild: "Sender").queryEqual(toValue: self.items[indexPath.row].Sender)
// check the sender value
myRequestRef.observeSingleEvent(of: .value, with: { (snapshot) in
//get the sender key
let senderKey = snapshot.key as String
// create status ref for new status value
let statusRef = FIRDatabase.database().reference().child("requests").child(senderKey)
// create new dict for status value
let newValue = ["Status": 2] as [String: Any]
statusRef.updateChildValues(newValue, withCompletionBlock: { (error, _) in
if error != nil {
print(error?.localizedDescription ?? "Failed to set status value")
}
print("Successfully set status value")
// Update your UI
DispatchQueue.main.async {
// Do anything with your UI
}
})
}) { (error) in
print("Failed to get snapshot", error)
}
Try moving your code inside .observe. This will allow you to get the status and check that it's accessing the right child. By using the child path below, it will override the status value but not the rest of the values inside the child.
self.ref?.child("requests").queryOrdered(byChild: "Sender").queryEqual(toValue: self.items[indexPath.row].Sender).observe(.value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
if value != nil {
print(value)
print(value["status"])
// If status is what you want, and prints out the correct status and
// correct child item
// Update the status
self.ref.child("requests/\(self.items[indexPath.row].Sender)/status").setValue("2")
}
})
I haven't tested the code above, but you should be able to make minor tweaks to get it to work in your code and on your firebase database.
You can update status value as below:
self.ref?.child("requests").queryOrdered(byChild: "Sender").queryEqual(toValue: self.items[indexPath.row].Sender).observe(.value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
if value != nil {
self.ref.child("requests/(self.items[indexPath.row].Sender)").updateChildValues(["status":"2"])
}
})
I'm using Firebase and I want to query to see if something exists. It gets called when a value is found, but the block does not get called when nothing is found. Is this expected behaviour?
ref.queryOrderedByKey().queryEqualToValue(channelName).observeSingleEventOfType(.ChildAdded, withBlock: { snapshot in
print("found channel: \(snapshot.key)")
}, withCancelBlock: { error in
print(error.description)
})
Have I done something wrong? Thanks
To check for no data (snapshot == NULL) it's done this way
let refToCheck = myRootRef.childByAppendingPath(channelNameString)
refToCheck.observeEventType(.Value, withBlock: { snapshot in
if snapshot.value is NSNull {
print("snapshot was NULL")
} else {
print(snapshot)
}
})
Queries are pretty heavy by comparison to the .observeEventType and since you already know the specific path you are checking for it will perform much better.
Edit: You can also use
if snapshot.exists() { ... }
Firebase queries are best used when you want to retrieve child nodes that contain specific values or a range of values.
Edit for Firebase 3.x and Swift 3.x
let refToCheck = myRootRef.child(channelNameString)
refToCheck.observe(.value, with: { snapshot in
if snapshot.exists() {
print("found the node")
} else {
print("node doesn't exist")
}
})
Note 1) the logic was changed a bit as we now leverage .exists to test for existence of a snapshot.
Note 2) this code leaves an observer active in Firebase so if the node is created at a later time, it will fire.
If you want to check for a node and don't want to leave an observer watching for that node do this:
let refToCheck = myRootRef.child(channelNameString)
refToCheck.observeSingleEvent(of: .value, with: { snapshot in
if snapshot.exists() {
print("found the node")
} else {
print("node doesn't exist")
}
})