I am creating an app similar to Instagram. I created a logged in user feed tab with this code
FIRDatabase.database().reference().child("posts").child(self.loggedInUser!.uid).observeSingleEvent(of: .value, with: { (snapshot:FIRDataSnapshot) in
let key = snapshot.key
let snapshot = snapshot.value as? NSDictionary
snapshot?.setValue(key, forKey: "uid")
print(snapshot)
if(key == self.loggedUser?.uid)
{
print("same as logged in user")
}
else
{
self.usersArray.append(snapshot)
self.followUsersTableView.insertRows(at: [IndexPath(row:self.usersArray.count-1,section:0)], with: UITableViewRowAnimation.automatic)
}
}) { (error) in
print(error.localizedDescription)
}
However, I want to create a tab that outputs all the users in the database posts, but when I use this code
FIRDatabase.database().reference().child("posts").observeSingleEvent(of: .value, with: { (snapshot:FIRDataSnapshot) in
It doesn't work.
My Firebase database looks like this
Is there a way I can access the title node of all the users and not only the logged in users.
You can do it like this
FIRDatabase.database().reference().child("posts").observeSingleEvent(of: .value, with: { (snapshot) in
for child in snapshot.children {
if let item = child as? FIRDataSnapshot {
// get values
let foo = item["index"] as? String
}
}
}
Related
JSON
switch
uid
switch : true
uid2
switch : false
What I tried that doesn't work
#objc func didLongPress() {
let databaseRef = Database.database().reference().child("switch").child(self.postID)
databaseRef.queryOrdered(byChild: "switch").queryEqual(toValue: "true").observeSingleEvent(of: .value) { (snapshot) in
print(snapshot)
if snapshot.exists() {
print("Address is in DB")
} else {
print("Address doesn't exist")
}
}}
//////note it picks up self.postID successfully so error is after that. print snapshot gives null
also tried
let databaseRef = Database.database().reference().child("switch").child(self.postID).child("switch/\true")
databaseRef.observeSingleEvent(of: .value) { (snapshot) in
print(snapshot)
if snapshot.exists() {
print("Address is in DB")
} else {
print("Address doesn't exist")
}
}
}
So in theory this should be a really easy, elementary task. The first of the above mentioned attempts should work. There are no permission errors, but console simply produce null as the snapshot print. That is so weird.
If I test a simple snapshot to see what prints with .child(switch).child(self.postID).child(switch) - it prints either 1 for true and 0 for false. So that works.
EDIT: I think this is because it is in an objective c function. I just realized that. I need it in objective C, because if gets called on long press, which uses objective c function
Try:
(Change database child path as per your need.)
Database.database().reference().child("switch").child(self.postID).queryOrdered(byChild: "switch").queryEqual(toValue: true).observeSingleEvent(of: .value, with: { (snapshot) in
if let dict = snapshot.value as? [String: AnyObject] {
print("Address is in DB")
} else {
print("Address doesn't exist")
}
}) { (error) in
print(error.localizedDescription)
}
As the user types text into the searchBar the UISearchController has a delegate method to update search results:
func updateSearchResults(for searchController: UISearchController) {
guard let searchText = searchController.searchBar.text?.lowercased() else { return }
Database...usersRef
.queryOrdered(byChild: "username")
.queryStarting(atValue: searchText)
.queryEnding(atValue: searchText+"\u{f8ff}")
.observe( .childAdded, with: { [weak self](snapshot) in
let key = snapshot.key
guard let dict = snapshot.value as? [String: Any] else { return }
let user = User(userId: key, dict: dict)
self?.datasource.append(user)
})
}
That works fine.
When I normally paginate I use this procedure:
var startKey: String?
func handlePaginationForPosts() {
if startKey == nil {
Database...PostsRef
.queryOrderedByKey()
.queryLimited(toLast: 10)
.observeSingleEvent(of: .value, with: { [weak self] (snapshot) in
guard let children = snapshot.children.allObjects.first as? DataSnapshot else { return }
if snapshot.childrenCount > 0 {
for child in snapshot.children.allObjects as! [DataSnapshot] {
let postId = child.key
if child.key != self?.startKey {
guard let dict = child.value as? [String:Any] else { return }
let post = Post(postId: postId, dict: dict)
self?.datasource.insert(post, at: 0)
}
}
self?.startKey = children.key
}
})
} else {
let lastIndex = datasource.count
Database...PostsRef
.queryOrderedByKey()
.queryEnding(atValue: startKey!)
.queryLimited(toLast: 11)
.observeSingleEvent(of: .value, with: { [weak self] (snapshot) in
guard let children = snapshot.children.allObjects.first as? DataSnapshot else { return }
if snapshot.childrenCount > 0 {
for child in snapshot.children.allObjects as! [DataSnapshot] {
let postId = child.key
if child.key != self?.startKey {
guard let dict = child.value as? [String:Any] else { return }
let post = Post(postId: postId, dict: dict)
// I run a check to make sure the datasource doesn't contain the post before adding it
self?.datasource.insert(post, at: lastIndex)
}
}
self?.startKey = children.key
}
})
}
}
The problem here is when running a search I use:
.queryStarting(atValue: searchText)
.queryEnding(atValue: searchText+"\u{f8ff}")
But when paginating a post I use:
.queryOrderedByKey()
.queryEnding(atValue: startKey!) ...
self?.datasource.insert(post, at: lastIndex)
The startKey is the first key in the snapshot.children.allObjects.first and the lastIndex is the datasource.count.
Considering the search query is based on the search text and not a key, how can I paginate when I'm already using .queryEnding(atValue: searchText+"\u{f8ff}") instead of .queryEnding(atValue: startKey!)?
I need to track the key that was pulled from the db so that when I paginate I can run the next set of results from that particular key.
Firebase Database queries can only order/filter on a single property.
So what you can do is filter for the search criteria, and then limit to the firsts N results.
What you can't do is filter for the search criteria, skip the first N results, and get the next page.
The closest you can get, and something regularly done for cases such as this, is retrieve the first 2*N results when you need to show page 2. This wastes some bandwidth though, so you'll have to trade that off against how useful the pagination is.
I am working on the user profile page of my app, where the user can make changes to the user info, like change their username, name... Each user has their own unique username, I have done that with the following code:
// Function to check if the username is taken
static func checkUsernameUnique(newUserName: String, completion: #escaping(Bool) -> Void) {
let ref = Database.database().reference()
ref.child("Users").queryOrdered(byChild: "Username").queryEqual(toValue: newUserName).observeSingleEvent(of: .value, with: {(snapshot: DataSnapshot) in
if snapshot.exists() {
completion(true)
} else {
completion(false)
}
})
}
This checks if there is a user with the same username. Calling this function:
checkUsernameUnique(newUserName: username) { isExist in
if isExist {
print("Username is taken")
} else {
print("Username is not taken")
}
}
The problem with this is that this checks if there is a user using the same username with all the other users in the database, including the current user. How do I exclude the current user?
Code that I tried with the help of one of the answers
static func checkUsernameUnique(newUserName: String, completion: #escaping(Bool) -> Void) {
let ref = Database.database().reference()
if let userID = Auth.auth().currentUser?.uid {
print(userID)
ref.child("Users").queryOrdered(byChild: "Username").queryEqual(toValue: newUserName).observeSingleEvent(of: .value, with: {(snapshot: DataSnapshot) in
if !snapshot.exists() {
completion(false)
} else {
//Here we will check the given user's UID
snapshot.ref.child("UserID").observeSingleEvent(of: .value, with: { (uidSnapshot) in
//This forced cast should never fail
let uid = uidSnapshot.value as! String
print(uid)
//Now we use FirebaseAuth to cross reference the current user's UID with whatever the "Username" node's sibling node "UserID" is
if Auth.auth().currentUser!.uid == uid {
//The returned user is the same as the current user
completion(false)
} else {
//The returned user is not the same as the current user
completion(true)
}
})
}
})
} else {
ref.child("Users").queryOrdered(byChild: "Username").queryEqual(toValue: newUserName).observeSingleEvent(of: .value, with: {(snapshot: DataSnapshot) in
if snapshot.exists() {
completion(true)
} else {
completion(false)
}
})
}
}
Try this. All we have to do is get the userID of whatever is returned from the query, and check if it equals the current user's uid.
// Function to check if the username is taken
static func checkUsernameUnique(newUserName: String, completion: #escaping(Bool) -> Void) {
let ref = Database.database().reference()
ref.child("Users").queryOrdered(byChild: "Username").queryEqual(toValue: newUserName).observeSingleEvent(of: .value, with: {(snapshot: DataSnapshot) in
guard let json = snapshot.value as? [String:[String:Any]] else {
completion(false)
return
}
//Assuming there will never be more than one database entry with this username, this first element (result) can be unwrapped explicitly without crashing
let result = json.first!.value
let userID = result["UserID"] as! String
if Auth.auth().currentUser!.uid == uid {
completion(false)
} else {
completion(true)
}
})
}
There is no way to conditionally exclude data from a query. You will have to check in your client code if specific data is present in the result, and exclude it from there. Just checking snapshot.exists will not be sufficient in your case - instead, look inside the snapshot to see if it contains the UID of the current user.
I wanted to delete this record in firebase, where i don't have the name of the key. so, I don't know how to do it. can anybody help me with this?
The code for getting array is as follows
var databaseRefer : DatabaseReference!
let userID = Auth.auth().currentUser?.uid
databaseRefer = Database.database().reference(withPath: userID!)
databaseRefer.observeSingleEvent(of: .value, with: { snapshot in
if !snapshot.exists() { return }
if snapshot.value is NSNull {
print("not found")
} else {
for child in snapshot.children {
let snap = child as! DataSnapshot
print(dict)
dict.forEach { item in
print(item.value)
}
}
}
})
https://firebase.google.com/docs/database/ios/read-and-write
"The simplest way to delete data is to call removeValue on a reference to the location of that data."
I'm trying to retrieve specific data from just the currently logged in user. My data in my database looks like this:
For example, I want to just grab the full_name and save it in a variable userName. Below is what I'm using to grab my data
ref.queryOrderedByChild("full_name").queryEqualToValue("userIdentifier").observeSingleEventOfType(.ChildAdded, withBlock: { snapshot in
print(snapshot.value)
// let userName = snapshot.value["full_name"] as! String
})
Unfortunately, this is what my console prints.
I would appreciate any help :) Thank you!
It gives you that warning message indexOn because you are doing a query.
you should define the keys you will be indexing on via the .indexOn
rule in your Security and Firebase Rules. While you are allowed to
create these queries ad-hoc on the client, you will see greatly
improved performance when using .indexOn
As you know the name you are looking for you can directly go to that node, without a query.
let ref:FIRDatabaseReference! // your ref ie. root.child("users").child("stephenwarren001#yahoo.com")
// only need to fetch once so use single event
ref.observeSingleEventOfType(.Value, withBlock: { snapshot in
if !snapshot.exists() { return }
//print(snapshot)
if let userName = snapshot.value["full_name"] as? String {
print(userName)
}
if let email = snapshot.value["email"] as? String {
print(email)
}
// can also use
// snapshot.childSnapshotForPath("full_name").value as! String
})
Swift 4
let ref = Database.database().reference(withPath: "user")
ref.observeSingleEvent(of: .value, with: { snapshot in
if !snapshot.exists() { return }
print(snapshot) // Its print all values including Snap (User)
print(snapshot.value!)
let username = snapshot.childSnapshot(forPath: "full_name").value
print(username!)
})
{
"rules": {
"tbl_name": {
".indexOn": ["field_name1", "field_name2"]
},
".read": true,
".write": true
}
}
You can apply indexOn on any field. Add this json in rules security and rules tab.
Hope this works for you. :)
It retrieves logged in user data:
let ref = FIRDatabase.database().reference(fromURL: "DATABASE_URl")
let userID = FIRAuth.auth()?.currentUser?.uid
let usersRef = ref.child("users").child(userID!).observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot)
let ref = Database.database().reference().child("users/stephenwarren001#yahoo.com")
ref.observeSingleEvent(of: .value, with: { (snap : DataSnapshot) in
print("\(String(describing: snap.value))")
}) { (err: Error) in
print("\(err.localizedDescription)")
}
var refDatabase = DatabaseReference()
refDatabase = Database.database().reference().child("users");
let refUserIdChild = refDatabase.child("stephenwarren001#yahoo.com")
refUserIdChild.observeSingleEvent(of: .value, with: { snapshot in
if !snapshot.exists() { return }
print(snapshot) // Its print all values including Snap (User)
print(snapshot.value!)
if let tempDic : Dictionary = snapshot.value as? Dictionary<String,Any>
{
if let userName = tempDic["full_name"] as? String {
self.tfName.text = userName
}
if let email = tempDic["email"] as? String {
self.tfEmail.text = email
}
}
})