Unrecognized selector while removing all user posts from Firebase - swift

I tried to delete all posts that belongs to specific user, however it crashes telling me error:
'-[FIRDataSnapshot removeValue]: unrecognized selector sent to
instance 0x174238c20'
but if I try to po the child, it prints out the child.
That is how I am doing it in Swift3:
FIRDatabase.database().reference().child("posts").queryEqual(toValue: self.currentUser.generalDetails.userName).ref.observe(.value, with: { (snapshot: FIRDataSnapshot!) in
for child in snapshot.children {
(child as AnyObject).removeValue() //This line gives the error.
}
})
That is the child that shold be removed if "username":"currentUser.generalDetails.userName":
posts
-KUaMd3YgJlQvv_P-kdK//This has to be deletod with all its children
content:
likes:
postId:
postImageStringUrl: close
profileImageUrl:
timestamp:
username:
Wha should cause the crash?
Edit: I updated code like this which says that I have to :
Consider adding ".indexOn": "posts/username" at / to your security
rules for better performance
however I have pretty ok security rules:
{
"rules": {
".read": "auth != null",
".write": "auth != null",
"Snuses": {
".indexOn": ["Brand", "posts/username"]
}
}
}
FIRDatabase.database().reference().queryOrdered(byChild: "posts/username").queryEqual(toValue: currentUser.generalDetails.userName)
.observeSingleEvent(of: .value, with: { snapshot in
if ( snapshot.value is NSNull ) {
print("not found")
} else {
for child in (snapshot.children) {
let element = child as! FIRDataSnapshot //the node data
let key = element.key //the key for the node
let nodeToRemove = FIRDatabase.database().reference().child(key)
nodeToRemove.removeValue()
}
}
})

I believe you are going to want to remove child by it's parent key, not the child.
Frank provided a short comment (which is actually THE answer) but here's a verbose example (Firebase 2.x but you'll get the idea):
ref.queryOrdered(byChild: "posts/username").queryEqual(toValue: "someUsername")
.observeSingleEvent(of: .value, with: { snapshot in
if ( snapshot?.value is NSNull ) {
print("not found")
} else {
for child in (snapshot?.children)! {
let element = child as! FDataSnapshot //the node data
let key = element.key! //the key for the node
let nodeToRemove = ref.child(byAppendingPath: key)
nodeToRemove?.removeValue()
}
}
})
something to look for is to make sure your paths are correct.
In the above code, 'key' is the parent node name like
-KUaMd3YgJlQvv_P-kdK
If you were to use
let ref = element.ref
it would be the specific path to that node, including the node name but no other data, like this
root_node/posts/-KUaMd3YgJlQvv_P-kdK
so the idea is once you have that reference, use use the reference to remove the node.
So if ref = root_node/posts/-KUaMd3YgJlQvv_P-kdK
then ref.remove(), it will remove that reference and the child data.

Although #Jay's answer does your job, but i was half way through already writing your answer, Give it a shot and let me know:-
let refe = FIRDatabase.database().reference().child("posts")
refe.queryOrdered(byChild: "username").queryEqual(toValue: currentUser.generalDetails.userName).observeSingleEvent(of: .value, with: { (snapshot) in
if let snapDict = snapshot.value as? [String:AnyObject]{
for each in snapDict {
print(each.key)
refe.child(each.key).removeValue(completionBlock: { (err, ref) in
print(ref)
})
}
}
}, withCancel: {(errO) in
})
It should delete every posts that the user made.. :)

Related

Firebase swift not retrieving all child values

I have a piece of code inside my Swift built iOS app, to retrieve all the nodes from a Firebase Realtime database. When I execute the code below I've noticed that it does not return all the child nodes.
When I query the particular nodes which are not being returned individually, at first the code returns 'nil' and then on a second attempt retrieves the nodes. (without doing any code changes in the process). Following this process, the node starts to show up in the results with the retrieve all nodes function.
Example 1: First returns nil, then on a second attempt returns the node. Which I can see from the console and definitely exists on the database.
ref?.child("transactions").child(email).child("14526452327").observeSingleEvent(of: .value, with: { (snapshot) in
// Get user value
let value = snapshot.value as? NSDictionary
print(value)
print("!!****************!!")
// ...
}) { (error) in
print(error.localizedDescription)
}
The following is being used to retrieve all child values; at first this doesn't get all the nodes, however after running the code from Example 1 (twice) it starts to return the node in question.
ref?.child("transactions").child(email).observeSingleEvent(of: .value, with: { (snapshot) in
let childrenCount = snapshot.childrenCount
var counter : Int = 0
for trans in snapshot.children.allObjects as! [DataSnapshot]
{
counter = counter + 1
self.ref?.child("transactions").child(email).child(trans.key).observeSingleEvent(of: .value, with: { (snapshot2) in
I've also checked my Firebase query and data limits and I am nowhere near the threshold for the free account. Any help is greatly appreciated.
Try this:
func getData() {
// Making a reference
let transactionRef = Database.database().reference(withPath: "transactions")
transactionRef.observeSingleEvent(of: .value, with: { (snapshot) in
// Printing the child count
print("There are \(snapshot.childrenCount) children found")
// Checking if the reference has some values
if snapshot.childrenCount > 0 {
// Go through every child
for data in snapshot.children.allObjects as! [DataSnapshot] {
if let data = data.value as? [String: Any] {
// Retrieve the data per child
// Example
let name = data["name"] as? String
let age = data["age"] as? Int
// Print the values for each child or do whatever you want
print("Name: \(name)\nAge: \(age)")
}
}
}
})
}

How to get parent from child

So let's say I found that a value in database matches value entered by user through query. How can I find the parent of that value?
Ex. Let's say I enter in 35 as the age. 35 is also found in the database so how do I get the parent of that value (0)? Underlined in the picture.
I saw some similar questions asked but I can't seem to find a right answer to my question. Additionally, most of them are in different language.
Here is what I got so far:
#IBAction func onDiagnose(_ sender: Any) {
let ref1 = Database.database().reference(fromURL: "https://agetest.firebaseio.com/")
let databaseRef = ref1.child("data")
databaseRef.queryOrdered(byChild: "age").queryEqual(toValue: Int(ageTextField.text!)).observeSingleEvent(of: .value, with: { (snapshot) in
// if there is data in the snapshot reject the registration else allow it
if (snapshot.value! is NSNull) {
print("NULL")
} else {
//print(snapshot.value)
//get parent
//snapshot.ref.parent?.key! as Any
}
}) { (error) in
print(error.localizedDescription)
}
}
When you execute a query against the Firebase Database, there will potentially be multiple results. So the snapshot contains a list of those results. Even if there is only a single result, the snapshot will contain a list of one result.
So you need to loop through the child nodes of the resulting snapshot to get at the individual results:
databaseRef.queryOrdered(byChild: "age").queryEqual(toValue: Int(ageTextField.text!)).observeSingleEvent(of: .value, with: { (snapshot) in
for child in snapshot.children.allObjects as! [DataSnapshot] {
print(child.key)
}
}) { (error) in
print(error.localizedDescription)
}
Also see listening to value events for lists of data in the Firebase documentation.

I want to search in firebase through user name

I am facing an issue in retrieving a data present in node
Dev->Regis->[userId("hjgsfgsdfghd8ydfsw3r")]->UserInfo->{userName:"", email:""}
I am trying the following query
ref.child(kChild).child(kRegistration).queryOrdered(byChild: kUserInfo).queryEqual(toValue: searchText).observeSingleEvent(of: .value) { (snapshot) in
if snapshot.exists() {
}
}
I also tries by making rules but it does make result
"Development": {
"Registration": {
"$user_id": {
"UserInfo": {
".indexOn": ["userName"],
".read": "auth.uid == $user_id"
}
}
}
}
database structure
and ref means Database.refrence()
Please help to sort out this problem.
Thanks.
Assuming searchText is the username value that you want to grab the object for. Firebase requires an orderBy call.
let searchText = //username you wish to fetch
let ref = db.ref('Development/Registration/${userId}/userInfo')
ref.orderByChild('userName').equalTo(searchText).once("value", function(snapshot) {
if(snapshot.exists()){
//whatever you want to do here
}
}

Iterate through emails in Firebase - Swift

I am currently trying to iterate through all user emails in firebase, however, whenever I run my code, and try to add the "test#gmail.com" user, there is an error. However, when I try to add my current user's email address, "test1#gmail.com", there is a success.
Below is a snippet of my code demonstrating this. B
Below is also an image showing the structure of my current database.
Note that each user's email is under a unique userID under the "users" part of the database.
Iterating through email snippet.
func searchEmails() {
var ref : DatabaseReference
let currentUserID = Auth.auth().currentUser?.uid
ref = Database.database().reference()
let userRef = ref.child("users")
userRef.observeSingleEvent(of: .value, with: { snapshot in
let enumerator = snapshot.children
while let rest = enumerator.nextObject() as? DataSnapshot {
userRef.child(rest.key).child("email").observe(.value, with: { snapshot in
print(snapshot.value!)
// print("Other rest is this \(otherRest.value!) value")
if(snapshot.value as? String == self.shareEmail.text) {
SVProgressHUD.showSuccess(withStatus: "Request sent to user!")
}
else {
SVProgressHUD.showError(withStatus: "Email not valid.")
}
})
}
})
SVProgressHUD.dismiss()
}
Why don't you try this, Might turn out to be much less headache.. :-
if self.shareEmail.text != "" && self.shareEmail.text.isEmpty == false{
Database.database().reference().child("users").queryOrdered(byChild: "email").queryEqual(toValue: "somemail").observe(.value, with: {(Snapshot) in
if Snapshot.exists(){
// The email that you have been searching for exists in the
// database under some particular userID node which can
// be retrieved from ....
print(Snapshot)
}else{
// No such email found
}
}, withCancel: {(error) in
// Handle any error occurred while making the call to firebase
})
}else{
//Your textfield must not be empty;.... Handle that error
}
Note : This is only gonna work if Firebase Security rules allow it... so you might have to work on that on your console... Good luck!

Unique usernames in Firebase

I have been trying to implement Chris’ answer here: Can I make Firebase use a username login process? for the Facebook login but I can’t seem to get my head around it.
So far I’ve tried to set conditions on the textField but as Firebase observer works asynchronously, the conditions to check if the username exists in the database won’t work.
let usernameString = usernameTextField.text
let uid = FIRAuth.auth()?.currentUser?.uid
ref.runTransactionBlock({ (currentData: FIRMutableData) -> FIRTransactionResult in
if var post = currentData.value as? [String : AnyObject], let uid = FIRAuth.auth()?.currentUser?.uid {
let usernamesDictionary = post["usernames"] as! NSDictionary
for (key, _) in usernamesDictionary {
if key as? String == usernameString {
print("username not available: \(key)")
}
else if usernameString == "" {
print("Uh oh! Looks like you haven't set a username yet.")
}
else if key as? String != usernameString {
print("username available: \(key)")
print("All set to go!")
let setValue: NSDictionary = [usernameString!: uid]
post["usernames"] = setValue
currentData.value = post
}
}
return FIRTransactionResult.successWithValue(currentData)
}
return FIRTransactionResult.successWithValue(currentData)
}
Then I tried creating /usernames/ node in the database and set up rules as:
{
"rules": {
"usernames": {
".read": "auth != null",
".write": "newData.val() === auth.uid && !data.exists()"
}
}
}
Now that won’t let me set any username to the database. I get confused in creating rules but my whole point is that I need a sign up flow with the username data that’s unique for each user in the database.
While trying every answer I found in related posts, what worked for me the easy way i.e. without making Firebase rules play a part in it or creating a separate usernames node in the database was to not put an if/else condition inside the Firebase observer but instead to use the exists() method of FIRDataSnapshot.
Now here’s the trick, while I did try only the exists() method with a simple observer but that did not help me. What I did was first query usernames in order, then match the username with queryEqualToValue to filter the query:
refUsers.queryOrderedByChild("username").queryEqualToValue(usernameString).observeSingleEventOfType(.Value , withBlock: {
snapshot in
if !snapshot.exists() {
if usernameString == "" {
self.signupErrorAlert("Uh oh!", message: "Looks like you haven't set a username yet.")
}
else {
// Update database with a unique username.
}
}
else {
self.signupErrorAlert("Uh oh!", message: "\(usernameString!) is not available. Try another username.")
}
}) { error in
print(error.localizedDescription)
}
}
This is the first time out of most of the answers here that worked for me. But for now, I don’t know if this would scale. Post your experiences and best practices. They’ll be appreciated.