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!
Related
i am currently working on a project where users have accounts with information about them. And I want that every client can get and load the data with just the ID of the target. I wanted to solve this with a function, but i don't know how to return the data, I hope you can help me!
Screenshot Firebase
func getUserData(targetID: String)->String{
let db = Database.database(url: "link")
db
.reference()
.child("users")
.child(targetID)
.child("/username")
.getData(completion: { error, snapshot in
guard error == nil else {
print(error!.localizedDescription)
return;
}
let userName = snapshot.value as? String ?? "null";
});
return userName //won't work, but how can I make it work?
}
I want to achieve this:
This is my current database. It only shows 1 information but it should be showing 3 messages:
// loading the info onto firebase database
let uid = Auth.auth().currentUser?.uid
let ref = Database.database().reference()
ref.child("workout").observeSingleEvent(of: .value, with: { (snapshot) in
print("Got Snapshot")
print(snapshot.childrenCount)
let chilidCount = snapshot.childrenCount
print(chilidCount)
let post:[String:String] = ["\(chilidCount + 1)": textField.text!]
print(post)
ref.child("workout").child(uid!).setValue(post)
})
self.tableView.reloadData()
This is my code so far. I tried looking at other previous question from StackOverflow and also looked at firebase documentation but could not find anything useful.
This is my tableview
Try making a dictionary of the values you want to upload to your FIR Database.
I assume you want to upload the values to your database in a "workout" folder, and in that upload values for each user. You should do the following:
let uid = Auth.auth().currentUser?.uid
let ref = Database.database().reference()
//Reference to the location where the messages get saved to
let userWorkoutRef = ref.child("workout").child(uid!)
userWorkoutRef.observeSingleEvent(of: .value, with: { (snapshot) in
// Get the number of messages
let messagesCount = snapshot.childrenCount
//Making a dictionary: the key is the current number of messages plus one, the value is the current text entered in the text field
let valueToUpload = ["\(messagesCount + 1)": textField.text!]
//Uploading the dictionary to the database
userWorkoutRef.updateChildValues(valueToUpload) { (err, ref) in
if err != nil {
print(err!.localizedDescription)
return
} else {
print("success uploading data to db!")
}
}
}
I'm having trouble because I am loading a very big number of data entries (about 1000) in the form of users. Now, I fetch the users userIDs and insert their rows with the user data into my table view. The thing is, that currently my app waits until it has finished going through all the userIDs there are and only then starts inserting them. Here's the code:
let group = DispatchGroup()
for each in userIDs {
check(identifier: "DispatchGroup", text: "\(each) started")
Database.database().reference().child("user-data").child(each).observeSingleEvent(of: .value, with: { (snap) in
if let data = snap.value as? [String:AnyObject] {
if let name = data["name"] as? String, let urlToImage = data["imagePath"] as? String, let status = data["status"] as? String {
let newUser = User()
newUser.name = name
newUser.imagePath = urlToImage
newUser.status = status
self.usersTableView.append()
if let index = self.usersTableView.index(of: newUser) {
self.tableView.insertItems(at: [IndexPath(row: index, section: 0)])
check(identifier: "FeedLoad", text: "inserting user \(newUser.userName) at timestamp \(Date().timeIntervalSince1970)")
}
check(identifier: "DispatchGroup", text: "\(each) ended")
print("Reloading table view at \(Date().timeIntervalSince1970)")
group.leave()
}
}
})
}
Now, what that prints me out is this:
DispatchGroup: xRDlUIBAsqeI13ykVsEx9P7okph2 started
DispatchGroup: dFVZAQmPb0TRRD94sPR32FbYWyk1 started
DispatchGroup: xRDlUIBAsqeI13ykVsEx9P7okph2 ended
DispatchGroup: dFVZAQmPb0TRRD94sPR32FbYWyk1 ended
But I want it to say:
DispatchGroup: xRDlUIBAsqeI13ykVsEx9P7okph2 started
DispatchGroup: xRDlUIBAsqeI13ykVsEx9P7okph2 ended
DispatchGroup: dFVZAQmPb0TRRD94sPR32FbYWyk1 started
DispatchGroup: dFVZAQmPb0TRRD94sPR32FbYWyk1 ended
How do I achieve this?
There are a couple of ways to achieve this. Firebase has no completion handlers for that sort of stuff, but what you could do is if you have a small amount of IDs in for loop just do is nest it like this:
Database.database().reference().child("user-data").child(id1).observeSingleEvent(of: .value, with: { (snap) in
Database.database().reference().child("user-data").child(id2).observeSingleEvent(of: .value, with: { (snap) in
Database.database().reference().child("user-data").child(id3).observeSingleEvent(of: .value, with: { (snap) in
}
}
}
But if that data can vary, the other way of achieving this would be to store a dictionary of ids and Bool to check if finished.
var ids = ["id1" : false, "id2" : false, "id3" : false]
func getNext() {
// If all ids == true { return }
// if not, get the next id
Database.database().reference().child("user-data").child(id1).observeSingleEvent(of: .value, with: { (snap) in
ids["id1"] = true
getNext()
}
}
And also don't call Database.Database().reference() every request. Instead store it as a variable. Check this for more info : Firebase best practices
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.. :)
I'm have a key in my Firebase database called "users" which contain keys for email and name. I'm trying to create a simple query that will find a user based on email address, but the query is not returning any results.
let rootRef = FIRDatabase.database().reference()
let email = emailTextField.text
rootRef.child("users").queryEqualToValue(email, childKey: "users").observeEventType(.Value, withBlock: { snapshot in
if snapshot.exists() {
print("user exists")
} else if !snapshot.exists(){
print("user doesn't exist")
}
})
My console always prints "user doesn't exist" even if the email text field is identical to what is shown in my database.
Any ideas as to what's wrong?
Thanks!!
Try this:
let usersRef = self.rootRef.childByAppendingPath("users")
let email = emailTextField.text
usersRef.queryOrderedByChild("email").queryEqualToValue(email)
.observeEventType(.Value, withBlock: { snapshot in
if snapshot.exists() {
print("user exists")
} else {
print("user doesn't exist")
}
})
You need to be careful though... .Value will return all nodes that have an email address equal to the one you are looking for. In general that would be one, however, if there are 5, .Value will contain all 5 so it would be safer to iterate over the snapshot.
for child in snapshot.children {
let email = child.value["whatever key:value you want"] as! String
}