Firebase iOS .queryOrderedByChild and .queryEqualTo not working - ios

I'm trying to filter results from a Firebase database with a structure like this one.
chats
chatId
messages
messageId
userId: true
I need two queries, one that returns only messages with existing child userId (if it exists it will always be true), the other that returns only messages without it.
I'm trying with this two references and observing .childAdded event:
let messagesWithUser = FIRDatabase.database().reference(withPath: "chats").child(chat.id).child("messages").queryOrdered(byChild: userId).queryEqual(toValue: true).ref
let messagesWithoutUser = FIRDatabase.database().reference(withPath: "chats").child(chat.id).child("messages").queryOrdered(byChild: userId).queryEqual(toValue: NSNull()).ref
Currently the .childAdded event returns all messages without filtering.

In response to Dmitriy:
func blueRewardBalance(completeBlock: (value: Double) -> Void) {
let userRef = FIRAuth.auth()?.currentUser?.uid
var rewardBalance : Double! = 0.00
let purchaseRef = FIRDatabase.database().reference(withPath: "Reward/\(userRef!)")
purchaseRef.queryOrdered(byChild: "abc").observe(.value, with: { snapshot in
let dataSnapshot = snapshot.value as! [String: AnyObject]
rewardBalance = dataSnapshot["rewardCardBalance"] as! Double!
completeBlock(rewardBalance)
})
}

Found out the problem. I was using FIRDatabaseReference instead of FIRDatabaseQuery to observe changes...

Thank you Nicola. I need implement previous method into my function, but blueRewardBalance request parameters.
func blueRewardTransaction(purchaseValue: Double) {
let newBalance = blueRewardBalance(completeBlock: //what I need paste here?) - purchaseValue
let userRef = FIRAuth.auth()?.currentUser?.uid
let firebaseRef = FIRDatabase.database().reference()
firebaseRef.child("Reward/\(userRef!)").updateChildValues(["rewardCardBalance": newBalance])
}

Related

Access Multiple Nodes in Firebase Database

I am having a hard time pulling all my data from one of my nodes in my firebase database.
Here is how the node looks like in Firebase:
Considerations
-MEdUNZwVrsDW3dTrE6N
Company Description:
Company Image:
Company Name:
Decision Date:
Start Date:
Users
B2Z4DlZ8RucvEQhz2NSUkquqc5P2
Compensation:
PostNumber:
StoryNumber:
Under users there are going to be multiple people with different values for the compensation, post number, and storynumber. I have each user having a node called "user-considerations" that tags the unique id of the consideration each user is attached on and places it under their UID and tags a 1 next to it as the value. I am trying to access each specific user's info along with the other info in the node. Here is my code that I am using to call the information along with the struct I a using to capture the information:
STRUCT:
import UIKit
class ConsiderationInfo: NSObject {
var companyName: String?
var companyImage: String?
var companyDescription: String?
var decisionDate: String?
var startDate: String?
var compensation: String?
var postNumber: String?
var storyNumber: String?
}
CODE FOR OBSERVING INFO:
func updateConsiderationsArray() {
let uid = Auth.auth().currentUser?.uid
let ref = Database.database().reference().child("user-considerations").child(uid!)
ref.observe(.childAdded, with: { (snapshot) in
let considerationId = snapshot.key
let considerationReference = Database.database().reference().child("Considerations").child(considerationId)
considerationReference.observe(.value, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let considerationInfo = ConsiderationInfo()
//self.setValuesForKeys(dictionary)
considerationInfo.companyName = dictionary["Company Name"] as? String
considerationInfo.companyImage = dictionary["Company Image"] as? String
considerationInfo.companyDescription = dictionary["Company Description"] as? String
considerationInfo.decisionDate = dictionary["Decision Date"] as? String
considerationInfo.startDate = dictionary["Start Date"] as? String
self.considerationsInfo.append(considerationInfo)
self.considerationName.append(considerationInfo.companyName!)
self.filteredConsiderations.append(considerationInfo.companyName!)
self.considerationCollectionView.reloadData()
}
}, withCancel: nil)
})
}
I am trying to access the information under the user specific node, i.e. the specific user's compensation post number and story number. I am unaware of how to access all of this to append the struct.
Here is the node with the user-considerations:
As it sits, I am really not seeing anything super wrong with the code but there are few things that could be changed to make it more streamlined.
I would first change the Consideration Info class to make it more self contained. Add a convenience initializer to handle a firebase snapshot directly with some error checking.
class ConsiderationInfo: NSObject {
var companyName = ""
convenience init(withSnapshot: DataSnapshot) {
self.init()
self.companyName = withSnapshot.childSnapshot(forPath: "Company Name").value as? String ?? "No Company Name"
}
}
I would also suggest removing the .childAdded and .observe events unless you specifically want to be notified of future changes. Use .value and .observeSingleEvent instead. Keeping in mind that .childAdded iterates over each node in your database one at a time - .value reads them in all at the same time. If there is a limited amount of data, .value works well.
func updateConsiderationsArray() {
let fbRef = Database.database().reference()
let uid = Auth.auth().currentUser?.uid
let ref = fbRef.child("user_considerations").child(uid)
ref.observeSingleEvent(of: .value, with: { snapshot in
let allUidsSnap = snapshot.children.allObjects as! [DataSnapshot]
for uidSnap in allUidsSnap {
let considerationId = uidSnap.key
let considerationReference = fbRef.child("Considerations").child(considerationId)
considerationReference.observeSingleEvent(of: .value, with: { snapshot in
let considerationInfo = ConsiderationInfo(withSnapshot: snapshot)
self.considerationArray.append(considerationInfo)
// update your collectionView
})
}
})
}
What I am doing in the above is reading in the single node from user_considerations, which looks like this according to your quuestion
user_considerations
some_user_uid
a_user_uid
a_user_uid
and then mapping each child user to an array to maintain order
let allUidsSnap = snapshot.children.allObjects as! [DataSnapshot]
and then iterating over each, getting the uid (the key) of each node and getting that nodes data from the Considerations node.

How to read data from FireBase

I have problem reading from Firebase in Swift.
Here is my Firebase database:
and here is my code:
var ref: FIRDatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
NSLog("Reading from DB")
ref = FIRDatabase.database().reference()
self.ref?.child("Frais").observeSingleEvent(of: .value, with: { (snapshot) in
let value = snapshot.value as? [String: Int]
var frpx1 = (value?["frpx1"]!)!
var frpx10 = (value?["frpx10"]!)!
var frpx11 = (value?["frpx11"]!)!
var frpx12 = (value?["frpx12"]!)!
var frpx13 = (value?["frpx13"]!)!
var frpx14 = (value?["frpx14"]!)!
var frpx15 = (value?["frpx15"]!)!
var frpx16 = (value?["frpx16"]!)!
})
print(frpx1)
print(frpx10)
print(frpx11)
print(frpx12)
print(frpx13)
print(frpx14)
print(frpx15)
print(frpx16)
}
I did not find the problem.
I do not have the data from database in frpx1, ..., frpx16.
Your code have a couple of minor issues:
you are casting the returned value to [String: Int] when you should be using [String: Any] instead since not all values are String based.
you are printing the results outside the completion handler. You need to wait the handler to be called to then read the results (i.e., when the method observeSingleEvent returns Firebase is still processing your request).
Fixing both issues should get you going:
...
self.ref?.child("Frais").observeSingleEvent(of: .value, with: {
(snapshot) in
guard let value = snapshot.value as? [String: Any] else {
print("Snapshot type mismatch: \(snapshot.key)")
return
}
let frpx1 = value["frpx1"]
let frpx10 = value["frpx10"]
let frpx11 = value["frpx11"]
...
print(frpx1)
print(frpx10)
print(frpx11)
...
})
PS. I also improved your coding style a little to help prevent further issues ;)

adding a child to a child in Firebase Database with Swift

I am working with the following Firebase Database:
I add new chatIDs with the following code:
DatabaseReference.users(uid: self.uid).reference().child("chatIds/\(chat.uid)").setValue(chat.uid)
I need to add a single child to the individual "chatIDs" that is a random string that I will generate but I haven't worked with Firebase for that long so I am not sure how to do add children this far in. How can I write the code to do this?
Based on your database structure, a possible implementation of you want would be:
let ref = Database.database().reference()
// Generating the chat id
let refChats = ref.child("chats")
let refChat = refChats.childByAutoId()
// Accessing the "chatIds branch" from a user based on
// his id
let currentUserId = self.uid
let refUsers = ref.child("users")
let refUser = refUsers.child(currentUserId)
let refUserChatIds = refUser.child("chatIds")
// Setting the new Chat Id key created before
// on the "chatIds branch"
let chatIdKey = refChat.key
let refUserChatId = refUserChatIds.child(chatIdKey)
refUserChatIds.setValue(chatIdKey)
I think what you're looking for is this
let key = firebaseRef.child("users").child("\(String(describing: uid))").child("chatIds").childByAutoId().key
let timestamp = Int(Date().timeIntervalSince1970)
let child = ["key":key,
"name": name as String,
"date": birth as String,
"created": "\(timestamp)"]
firebaseRef.child("users").child("\(String(describing: uid!))").child("chatIds").child(key).setValue(child)
as example I'm saving the key, name, date, and created, as Childs of chatIds, with the childByAutoId, that generates you a random key, so you can locate it when searching the object.
import UIKit
import Firebase
class ChatListVC: UIViewController {
var ref: FIRDatabaseReference!
var messages: [FIRDataSnapshot]! = []
fileprivate var _refHandle: FIRDatabaseHandle?
override func viewDidLoad() {
super.viewDidLoad()
self.userDetail()
}
func userDetail(){
_refHandle = self.ref.child("users").child("child id").observe(.value, with: { [weak self] (snapshot) -> Void in
guard let strongSelf = self else { return }
guard let dict = snapshot.value as? [String:Any] else { return }
//access data from dict
let MyName = dict["MyName"] as? String ?? ""
})
}

Reading data from firebase (ios)

I have a small dataset in Firebase database, but unfortunately, I can't get read value from list correctly. Here is the structure of the database.
I just need to get the value of day and reference it to var. Thanks in advance.
var collnum = ""
ref = Database.database().reference()
let collid = ref.child("collid").child("day")
collid.observeSingleEvent(of : .value, with : {(Snapshot) in
print(Snapshot)
if let snapDate = Snapshot.value as? String{
collnum = snapDate
print(snapDate)
}
})
let database = FIRDatabase.database().reference()
database.child("collid").queryOrderedByKey().observe(.value, with:
{
if let value = snapshot.value as? [String: AnyObject]
{
let ui = value["day"] as! String
print(ui)
}
}
You can do something like this to read the data. This will read the data from the database and put into an array, allowing you to read the data.

Firebase Swift syntax

Can anyone help me convert this from JavaScript to Swift 3 syntax?
I am trying to get all of the clients a specific user has.
I have clients saved in their own node, then I have a list of clientIDs in each of the users.
I believe this code will work, as a similar situation was described in the guide it comes from, data organized in the same way, but it is not swift syntax, particularly .on and .once.
var usersREF =
new Firebase("https://awesome.firebaseio-demo.com/users");
var clientsREF =
new Firebase("https://awesome.firebaseio-demo.com/clients");
var currentUsersClients = userREF.child("userID").child("comments");
currentUsersClients.on("child_added", function(snap) {
clientsREF.child(snap.key()).once("value", function() {
// Render the clients on the link page.
));
});
Here is the data Structure on Firebase:
I suppose other ways to do it might be to grab the current Users clientIDs, then do a call for all clients. Filter them via the clientIDs.
Or
Grab the current users clientIDs, then loop through them, making specific calls to each individual client using the ID.
I just don't know if it is bad practice to make multiple calls like that to firebase within a for loop. Or even worse, to pull down much much more data than is neccesary then filter it.
Thanks for any help!
This will get the clients for uid_0, based on your structure
let userRef = ref.child("users/uid_0")
userRef.observeSingleEvent(of: .value, with: { snapshot in
let userDict = snapshot.value as! [String:AnyObject]
let clientsDict = userDict["clients"] as! [String:AnyObject]
for client in clientsDict {
let clientId = client.key
print(clientId)
}
})
Use this sample code to get your desired result
func getUsers(forUserID userID: String, completion: #escaping (User) -> Swift.Void, failure: #escaping () -> ()) {
if Auth.auth().currentUser != nil {
Database.database().reference().child("users").child(userID).observe(.childAdded, with: { (snapshot) in
if snapshot.exists() {
let receivedMessage = snapshot.value as! [String: Any]
let name = receivedMessage["name"] as? String ?? ""
let id = receivedMessage["id"] as? Double ?? 0.0
let profileurl = receivedMessage["url"] as? String ?? ""
completion(User(name: name, id: id, url: url))
} else {
failure()
}
})
} else {
failure()
}
}

Resources