Firebase query returns empty when data is there - swift

I have this RTDB I am trying to search my users in, from a path called users -> UID -> and then the user key/values. One of them being "username". I want to append these to an array to return in my table view but no matter what I do, I keep getting back nothing.
var userRef = Database.database().reference(withPath: "users")
func queryText(_ text: String, inField child: String) {
print(text)
userRef.queryOrdered(byChild: child)
.queryStarting(atValue: text)
.queryEnding(atValue: text+"\u{f8ff}")
.observeSingleEvent(of: .value) { [weak self] (snapshot) in
for case let item as DataSnapshot in snapshot.children {
//Don't show the current user in search results
if self?.currentUser?.uid == item.key {
continue
}
if var itemData = item.value as? [String:String] {
itemData["uid"] = item.key
self?.resultsArray.append(itemData)
print(self?.resultsArray)
}
}
self?.tableView.reloadData()
}
}
Edit: I have verified I am able to print out the snapshot, I am just not getting the usernames added to my resultsArray. Anyone have a clue why?
bio = " dfdf";
displayname = chattest4;
email = "test#test.com";
"first_name" = chattest4;
followers = 0;
following = 0;
"join_date" = "June 28, 2021";
languages = English;
"last_name" = test;
location = "United States";
profileImageURL = "hidjkfsf";
username = chattest4;

So I found out the issue. Some of the values in my database were not strings, but I had coded it to only look for Strings. Username was stored after these non-string values, so it never reached it. I just changed the array to [String:Any] and then it worked!
if var itemData = item.value as? [String:Any]

Related

How to query multiple fields with one value in Firebase?

I'm a newbie at firebase I have implemented a sample app that able to transfer point to each other after transfer success I also added two fields called "sender_name" and "receiver_name" but it's too difficult to get all transitions based on user login I found sample ways to do just add multiple where to it, its work fine if true both but that's not what I want I want whereOr like SQL as an example below
SELECT column1, column2, ...
FROM table_name
WHERE condition1 OR condition2 OR condition3 ...;
any solution help, please
func getUserTransition(){
// process
/*
1.get all transition from tm_members sender and receiver by current user login
2.
*/
guard let username = self.userSession?.username else {
return
}
print("username in user session : \(username)")
COLLECTION_TM_TRANSITIONS_UAT
.whereField("sender_name", isEqualTo: username)
.whereField("receiver_name", isEqualTo: username)
.getDocuments { documentSnapshot, error in
if error == nil {
guard let value = documentSnapshot?.documents else { return }
self.tmTransitions = value.map { (queryDocumentSnapshot) -> TmTransition in
let data = queryDocumentSnapshot.data()
let email = data["email"] as? String ?? ""
let is_sender = data["is_sender"] as? Bool ?? false
let point = data["point"] as? Int ?? 0
let username = data["username"] as? String ?? ""
let sender_id = data["sender_id"] as? String ?? ""
let receiver_id = data["receiver_id"] as? String ?? ""
let created_at = data["created_at"] as? Timestamp
let sender_name = data["sender_name"] as? String ?? ""
let receiver_name = data["receiver_name"] as? String ?? ""
print("username : \(email)")
return TmTransition(id: queryDocumentSnapshot.documentID, sender_id: sender_id, receiver_id: receiver_id, username: username, is_sender: is_sender, point: point, email: email,created_at: created_at,sender_name: sender_name,receiver_name: receiver_name)
}
}
else{
print("error during fetch data ")
}
}
}

How to find out if an attribute is in the table for a user?

I have a firebase table where I need to find out if an attribute exists in the table for a particular user. Table is structured like this:
Users
-Lf9xUh53VeL4OLlwqQo
username: "my#test.com"
price: "$100"
special: "No"
-L12345ff322223345fd
username: "my2#test.com"
special: "No"
I need to find out if the "price" has been added for a specific user. Can't seem to figure that one out!
In swift I need something like:
self.ref?.child("Users").queryOrdered(byChild: "username").queryEqual(toValue: username.text!).observe(.value, with: { (snapShot) in
if (snapShot.value! is NSNull) {
print("nothing found")
} else {
print("found it!")
print(snapShot)
let snapShotValue = snapShot.value as! [String:[String:Any]]
Array(snapShotValue.values).forEach { // error here if it doesn't exist
let price = $0["price"] as! String
self.userPrice.text = price
}}
})
But if the price doesn't exist I'm getting an error. Thanks for your help.
Use as? instead of as!
if let price = $0["price"] as? String {
print(price)
}
else {
print("No price")
}
Or shortly
self.userPrice.text = ($0["price"] as? String) ?? "No price"

Getting old value of field in Firestore with Swift 5

I'm trying to get the old value of a field when it is changed in Firestore. Is there any way to access what the previous value of a field is after it is changed? Here is my current code, I want to access the old nickName under .modified and print out what the new nickName is and also the old one.
db.collection("cities").whereField("state", isEqualTo: "CA").addSnapshotListener { querySnapshot, error in
guard let snapshot = querySnapshot else {
print("Error fetching snapshots: \(error!)")
return
}
snapshot.documentChanges.forEach { diff in
if (diff.type == .added) {
print("New city: \(diff.document.data())")
let nickName = myData["nickName"] as? String ?? ""
}
if (diff.type == .modified) {
let nickName = myData["nickName"] as? String ?? ""
}
if (diff.type == .removed) {
let nickName = myData["nickName"] as? String ?? ""
}
}
}
Unfortunately, that is not a feature of Firestore. What you can do is have another field oldNickName and using Firebase Functions, automatically update that when the nickName field is changed.
The best solution is storing nickName locally, so you can refer back to your local variable when nickName changes, accessing the newly updated one in the database and the previous nickName locally. Here is the updated code:
var nickNames = [String : String]()
db.collection("cities").whereField("state", isEqualTo: "CA").addSnapshotListener { snapshot, error in
guard error == nil, let snapshot = snapshot?.documentChanges else { return }
snapshot.forEach {
let document = $0.document
let documentID = document.documentID
let nickName = document.get("nickName") as? String ?? "Error"
switch $0.type {
case .added:
print("New city: \(document.data())")
nickNames[documentID] = nickName
case .modified:
print("Nickname changed from \(nickNames[documentID]) to \(nickName)")
nickNames[documentID] = nickName
case .removed:
print("City removed with nickname \(nickNames[documentID])")
nickNames.removeValue(forKey: documentID)
}
}
}
nickNames is a dictionary with key cityID and value nickName. This code is written in Swift 5.

Firebase Swift 3 Fetching multiple values from a group

I want to be able to list users in a tableview by fetching their UID Value from a key stored in my database. As of now, the code only fetches the first value in the database rather than all of the values. Here is the code for fetching the applicants.
func loadApplicants() {
let usersRef = ref.child("users")
usersRef.observe(.value, with: { (users) in
var resultArray = [UserClass]()
for user in users.children {
let user = UserClass(snapshot: user as! DataSnapshot)
if user.uid == self.job.userID {
let appRef = self.ref.child("jobs").child(self.job.postID).child("applicants")
appRef.queryOrderedByKey().observeSingleEvent(of: .childAdded, with: { (snapshot) in
let sValue = snapshot.value
resultArray.append(user)
})
}
}
}) { (error) in
print(error.localizedDescription)
}
}
This is what my database looks like where the User's UIDs are stored.
jobs
"Job ID"
applicants:
-KtLJaQnFMnyI-MDWpys:"8R6ZAojX0FNO7aSd2mm5aQXQFpk1"
-KtLLBFU_aVS_xfSpw1k:"GGqjtYvwSwQw9hQCVpF4lHN0kMI3"
If I was to run the app, it fetches UID: "8R6ZAojX0FNO7aSd2mm5aQXQFpk1"
How can I implement a for loop or an if statement to ensure that all of the values are taken and appended into the table view
I know that I need a for loop before the fetchApplicants is called from AuthService because it is only fetching one UID but I can't work out where it would go.
Thanks.
P.S. This is what I have tried
func loadApplicants() {
let jobID = job.postID
let appRef = ref.child("jobs").child(jobID!).child("applicants")
appRef.queryOrderedByKey().observeSingleEvent(of: .childAdded, with: { (snapshot) in
if let applicants = snapshot.value! as? [String:AnyObject] {
for (value) in applicants {
self.authService.fetchApplicants(applicantID: "\(value!)", completion: { (users) in
self.usersArray = users
self.tableView.reloadData()
})
}
}
})
}
but the output is:
(key: "-KtLLBFU_aVS_xfSpw1k", value: GGqjtYvwSwQw9hQCVpF4lHN0kMI3)
(key: "-KtLJaQnFMnyI-MDWpys", value: 8R6ZAojX0FNO7aSd2mm5aQXQFpk1)
Needed to use observe instead of observeSingleEvent
Answer:
appRef.queryOrderedByKey().observe(.childAdded, with: { (snapshot) in

how to get the .child key in an array?

I want to take the save all of my blocked user child as a string in my code. But as simple as it might sound I was not able to figure it out.
static func block(myself: String, posterUID: String){
var blockedUserRef = Database.database().reference().child("users").child(myself).child("blockedUsers").child(posterUID)
blockedUserRef.setValue(true)
var blokedArray:[String] = []
var handle:DatabaseHandle!
blockedUserRef = Database.database().reference()
handle = blockedUserRef.child("blockedUsers").observe(.childAdded, with:{ (DataSnapshot) in
if let item = DataSnapshot.value as? String{
blokedArray.append(item)
}
})
}
I want to take the array of my blocked users go through in for loop and filter them from showing.
ref.observeSingleEvent(of: .value, with: { (snapshot) in
guard let snapshot = snapshot.children.allObjects as? [DataSnapshot]
else { return completion([]) }
// 3 filter the user from the array
let users =
snapshot
.flatMap(User.init)
.filter { $0.uid != currentUser.uid }
Here is my firebase:
"users" : {
"3YLVUDA8YnSuVYUTxv6cvOQPSjm1" : {
"username" : "🌸😍🌸"
},
"4duY2hhTv5S7sSXtZYBfiP7JBLz1" : {
"username" : "Love from NYC"
},
"58t0M2Fxxhg6GRT96vVbKMFHRKO2" : {
"blockedUsers" : {
"4duY2hhTv5S7sSXtZYBfiP7JBLz1" : true,
"SqarOdPJUydcdV6deXTeIdzkarE2" : true
},
"username" : "IStandWithYou"
},
some new ways I am trying I debugged it and it seems that it is not saving it onto the array
///adedblock
var blockedUserRef = Database.database().reference().child("users").child(currentUser.uid).child("blockedUsers")
var blokedArray:[String] = []
var handle:DatabaseHandle!
blockedUserRef = Database.database().reference()
handle = blockedUserRef.child("blockedUsers").observe(.childAdded, with:{ (DataSnapshot) in
if let item = DataSnapshot.value as? String{
blokedArray.append(item)
}
})
for user in blokedArray{
let users =
snapshot
.flatMap(User.init)
.filter { $0.uid != user }
}
This can be done by saving all of the child entries of blockedUsers to an array that will hold all your strings.
To do this, first create an empty array like
myList:[string] = []
Then, you need to create a reference to your Firebase database like:
var ref: DatabaseReference!
You also need a database handle to navigate around your database:
var handle:DatabaseHandle!
Now, you need to go to your ViewDidLoad function and add code like:
ref = Database.database().reference()
handle = ref?.child("blockedUsers").observe(.childAdded, with:{ (DataSnapshot) in
if let item = DataSnapshot.value as? String{
self.myList.append(item)
}
})
This piece of code is checking whether an entry is added to the child database "blockedUsers", and from that, it is adding whatever was just entered into the array.
Now, you have an array filled with whatever was in the child database, blockedUsers. You can now use the array in a UITableView, or list it in a label.
Hope this helped!