Why is firebase function only fetching once? - ios

I have a firebase fetch function which I call inside of a for loop. In it, I pass in variables postID and uid.
for child in snapshots.reversed() {
let keyValue = child.key
let uid = keyValue.split(separator: ":")[0]
let postIDDoubleVal = keyValue.split(separator: ":")[1]
print(String(uid), " This is the uid!!!!!!")
print(postIDDoubleVal, " This is tfdsafdsafdsafdsafads4!!!!")
self.fetchUsersPost(uid: String(uid), postID: "post:\(postIDDoubleVal)")
}
There are currently 2 users who's UIDs ARE successfully looped over.
The problem arrises when calling the function fetchUsersPost. For some reason for one of the loops (I believe the second) it works properly, but for the first it does not.
The beginning of the fetch function is:
func fetchUsersPost(uid: String, postID: String) {
print("fetchUsersPost Posts/\(uid)/\(postID)")
Here is the output:
fetchUsersPost Posts/QUocyvGehdeaOO9vVnklwOrWH7l1/post:580077760
QUocyvGehdeaOO9vVnklwOrWH7l1 This is the uid!!!!!!
580077723 This is tfdsafdsafdsafdsafads4!!!!
fetchUsersPost Posts/ QUocyvGehdeaOO9vVnklwOrWH7l1/post:580077723
I wonder if the problem is related to the fact that on one of the print statements (the second) there is a space between the uid and the '/'
What is the problem?

You have 1 user with UID = QUocyvGehdeaOO9vVnklwOrWH7l1 who has 2 posts with 580077760 and 580077723 , if there is a space you need to verify that you create the child key correctly when you set the value for it
let keyValue = child.key
as UID:POSTID with no leading , trailing or middle spaces , also make sure whether these 2 posts have a valid value before you fetch them

Related

Firebase Realtime Database querying not working

I'm trying to retrieve some values instead of others. In fact, I want to search for users by their names.
I've tried using queryStarting(atValue: input)and queryEnding(atValue: "u{f8ff}") but I couldn't find the right solution.
let input = searchInput.text?.lowercased()
print("Search for \(input!)")
let ref = Database.database().reference().child("Usernames").queryStarting(atValue: input).queryEnding(atValue: "u{f8ff}").queryOrderedByKey()
ref.observeSingleEvent(of: .value) { (snapshot) in
if snapshot.exists() {
for users in snapshot.children.allObjects as! [DataSnapshot] {
let user = users.value as? [String:AnyObject]
let id = user?["id"] as! String
Users.init(userId: (id))
print(users.key)
}
}
}
As you can see, I also added queryOrderedByKey(). If I don't add that part, it doesn't retrieve anything.
What I want is only retrieve the values starting by what I write in the textfield.
Usernames
----- charles
----------id: charles's uid
----- pierre
----------id: pierre's uid
----- bob
----------id: bob's uid
----- lu
----------id: lu's uid
The problem is that for example if the input is 'L' (to search for lu), it retrieves [lu]. Then if the input is 'Bo' (to search for bob), it retrieves [lu] and [bob], not only [bob] as I want. And obviously if the input is 'C' (to search for bob), it retrieves [lu], [bob], [pierre], and finally [charles].
Your current query starts at your input which is correct, but ends at u{f8ff} - meaning if you start bo, you'll also get words starting with c, d, etc.
What you need to do is end at the the highest value that starts with you string, e.g. for an input of bo you would want to end at bo\u{f8ff}. You can do this by concatenating your input with that unicode value, i.e.:
...queryEnding(atValue: input + "\u{f8ff}")... // <-- Also note that the unicode character is escaped here

Variable scope not what I want it to be? [duplicate]

This question already has an answer here:
Access Firebase variable outside Closure
(1 answer)
Closed 3 years ago.
I have a function bellow called retrieveUsers() which is called inside a function which fetches all posts under a Post node.
Inside the code found bellow I save the current UID to a variable with global scope. But every time this function gets called the variable (lastUID) seems to be reset. Even though this method is being called in a for-loop essentially.
func retrieveUsers(value: Post) {
print(lastUID, "-=-=--=-=")
print(value.user.userID != lastUID, ": ", value.user.userID!, " email left old ... one -> ", lastUID)
if value.user.userID != lastUID {//Ignore this line
let ref = Database.database().reference()
if value.user.userID != nil {
let UID = value.user.userID!
print(UID, "Thoi s is the uid in the users fetch fx")
ref.child("users2").child(UID).observe(.value, with: { (snapshot) in
let email = "\(snapshot.childSnapshot(forPath: "email").value as! String)"
do {
value.user.email = email
//even with the two values being in here the same thing happens
}
self.lastUID = UID
self.lastEmail = email
})
}
} else {
print("ESC this is the same user")
value.user.email = lastEmail
}
}
What is going wrong?
Even though this method is being called in a for-loop essentially.
The global var is changed every cycle of the for - loop and since the calls to firebase are asynchronous , hence you can't catch every fetch with it's corressponding UID
You need to create a model and make those calls inside it with a property as the uid

How to increment the value in specific node with firebase realtime database ios

Here i'm working in a chat application, i want to maintain the unread count for the recipient side. My json structre in console looks like
user_history
|
|--> user_a_uuid
|-> last_msg
|-> last_msg_timestamp
|-> unread_count
the scope of this question is, how to increment the value of unread_count. Prior incrementing i have the user_a_uuid and the node user_history & unread_count as a constant. So i tried as follows
dbRef.child("user_history")
.child(user_a_uuid)
.child("unread_count")
.runTransactionBlock { (unreadCount) -> TransactionResult in
var value = unreadCount.value as? Int
if value == nil {
value = 0
}
unreadCount.value = value! + 1
return TransactionResult.success(withValue: unreadCount)
}
Actually to be precise i borrowed this solution from here. I also tried to follow the doc. But the thing is that, i don't want to run transaction on the root node as in the doc. I want to run the transaction only on the unread_count doc.
Problem I'm facing:
After attempting this code, the problem i face is that, unread_count node getting deleted as soon and while i return the TransactionResult inside the completion block, it added unread_count. The problem is that the value is not incremented due to unread_count getting deleted. It always stays to 1.
Thanks in advance.
It appears you want to increment a counter stored in a node without affecting the other items in the node. Based on the information in the question there doesn't appear to be a need to use a transaction block in this use case due to the count being stored in code.
Prior incrementing i have the user_a_uuid and the node user_history &
unread_count as a constant
I believe this means you're storing unread_count in a variable in code so if that's correct, it simply needs to be incremented in code and written to the node.
Starting with a duplicate structure:
user_history
uid_0
last_msg: "some message"
last_msg_timestamp: "20181028075700"
unread_count: 2
and now we've added another message. The var needs to be incremented and then the corresponding node in Firebase need to be updated with the new value. Here's the code that does that:
func updateMsgCount() {
self.unread_count += 1 //this is a class var or however it's stored in code
let unreadCountRef = self.ref.child("user_history").child("uid_0").child("unread_count")
unreadCountRef.setValue(self.unread_count)
Suppose however, that the unread_count is not stored in code but only stored in Firebase. Here's the code to read in the unread_count node, increment the count and store it back in Firebase.
func updateCount() {
let unreadCountRef = self.ref.child("user_history").child("uid_0").child("unread_count")
unreadCountRef.observeSingleEvent(of: .value, with: { snapshot in
var currentCount = snapshot.value as? Int ?? 0
currentCount += 1
unreadCountRef.setValue(currentCount)
})
}
If you really need a transaction block, here's one to accomplish the same thing
func updateCountTransactionStyle() {
let unreadCountRef = self.ref.child("user_history").child("uid_0").child("unread_count")
unreadCountRef.runTransactionBlock( { (currentData: MutableData) -> TransactionResult in
var currentCount = currentData.value as? Int ?? 0
currentCount += 1
currentData.value = currentCount
return TransactionResult.success(withValue: currentData)
})
}

Firebase - updateChildValues crashes app when setting key in dictionary from constant

All I am trying to accomplish is setting the user's email string as a key in my database. My issue seems to be that the updateChildValues method crashes whenever I set the dictionary using a key that I have assigned to a constant - In this case userEmail. If I change the key to a string literal it works just fine, but that is not how I intend to structure this database node.
guard let uid = Auth.auth().currentUser?.uid, let email = Auth.auth().currentUser?.email else {
// handle
return
}
let groupId = UUID().uuidString
let userGroupIdValue = ["groupId": groupId]
let groupName = ["groupName": text]
let userEmail = [email: 1]
Database.database().reference().child("groups").child(groupId).child("memberEmails").updateChildValues(userEmail, withCompletionBlock: { (error, reference) in
// handle errors
})
If I change the userEmail dictionary to ["someText": 1] it works just fine, as do the constants userGroupIdValue and groupName. Through my troubleshooting, it seems as though this method does not like the fact that the email property in Auth.auth().currentUser? was previously an optional, even though I am using a guard statement. I have used if let statements to unwrap as well and it still crashes. Could this be a bug of sorts?
Well firebase support got back to me and it seems the issue is the email address that was unwrapped contained a "." in the string, and this character is not allowed to be used in a key in the database along with several other characters. Super frustrating but at least I have an answer.

Get the key from last child in Firebase

I need to be able to select randomly some data from my database on Firebase. For that and in order to avoid to download the whole database, I want to create entries with a key represented by an unsigned int like on this screenshot:
My question is, how can I retrieve the key of the last item added?
I tried:
ref.queryOrderedByKey().queryLimited(toFirst: 1).observeSingleEvent(of: .value, with: { [unowned self] snapshot in
let id: UInt64
if snapshot.exists(), let child = snapshot.children.nextObject() as? FIRDataSnapshot {
id = UInt64(child.key)!
} else {
id = 1
}
})
but UInt64(child.key)!, whether I use queryLimited(toFirst:) or queryLimited(toLast:), always returns 1.
What do I do wrong?
Your query returns the first result, which has key 1. You're looking for queryLimited(toLast: 1).
Additionally, in most cases, you should avoid numeric, sequential keys in distributed data.

Resources