Firebase queryEqualToValue - swift

I have the current Firebase Database structure.
I'd like to query all the true/false values.
Current code I have is;
let resultsRef = Database.database().reference().child("user_results").child(userID)
let query = resultsRef.queryOrderedByKey().queryEqual(toValue: "false")
query.observeSingleEvent(of: .value, with: { (snapshot) in
userID is "MyRQOZ..."
Printing out snapshot gives me nothing. However, if I do
.queryLimited(toFirst: 1)
I get the snapshot I want.
["yhgeZLXJhuXKmbnK1eRwkC4xmO84": false]
I believe on my ref I need to go one path further down. But I don't know what id would be.

You're only querying the first event
observeSingleEvent
Try
query.observe(.childAdded, with: { (snapshot) in
and add an if statement to catch the values
(Edit) Add this If Statement under the original bit of code that you have already, like this:
let resultsRef = Database.database().reference().child("user_results").child(userID)
let query = resultsRef.queryOrderedByKey().queryEqual(toValue: "false")
query.observeSingleEvent(of: .value, with: { (snapshot) in
if let trueOrFalse = snapshot.value as? [String: AnyObject] {
for (ke, value) in trueOrFalse {
if value as! String == "false" {
// 'ke' is now all of the keys where the value so you could do something like...
print(ke) //and it will give you the keys that have false as the value.

Related

Swift Retrieve Firebase Value from childByAutoID

I've read about a hundred posts on here about dealing with the value of "childByAutoId" children from Firebase's Realtime Database... but I haven't exactly found anything that would explain what I'm trying to do so I figured I'd finally break down and ask.
First off here's the database structure:
let database = Database.database().reference(withPath: "messages")
let db1 = database.child("sender").child("receiver").childByAutoId()
Pretty straightforward. I then wanted to retrieve the value of that autoID.
db1.observeSingleEvent(of: .value, with: { snapshot in
guard let value = snapshot.value as? [String: Any] else{
completion(.failure(DatabaseError.failedToFetch))
print("GetAll Failed")
return
}
...returns the "failedToFetch" error, while:
database.child("sender").child("receiver").observeSingleEvent(of: .value, with: { snapshot in
guard let value = snapshot.value as? [String: Any] else{
completion(.failure(DatabaseError.failedToFetch))
print("GetAll Failed")
return
}
...which is the same thing only excluding childByAutoId returns:
"-MrdAxlUKHvJWjtSQe7X": {
body = "cookies";
createdat = 1640294767943;
msgId = "-MrdAxlUKHvJWjtSQe7X";
name = glynis;
receiverUid = LKJHdhkjhkjsh;
senderUid = LAKSjksljlkajlk;
}
So now the data is coming in... but when I try to get the value of "-MrdAxlUKHvJWjtSQe7X" (the auto-generated key):
let things: [Thing] = value.compactMap({ dictionary in
guard let name = value["name"] as? String,
let msgId = value["msgId"] as? String,
let body = value["body"] as? String,
let receiverUid = value["receiverUid"] as? String,
let senderUid = value["senderUid"] as? String,
let createdat = value["createdat"] as? String,
let dated = value["dated"] as? String,)else {
return nil
}
And I do a:
guard !things.isEmpty else {
print("thing are empty")
return
}
They come up empty (even though "value" is certainly populated.) So my question is how would I properly retrieve the value of the generated key (childByAutoId)?
Some of the problems I spot:
Most of the fields in your value.compactMap( don't have a matching property in your snapshot just above it. E.g. createdat is not the same as value["created"], and there is no property tId in the snapshot.
The types need to match up in order to make the as? String cast work. Your createdat value is a long number (probably the number of milliseconds since the epoch), so casting that to a string leads to nil. You should cast it to a long/number value, or convert by calling the String function, as shown here: Convert Int to String in Swift
Based on your edit...
This code:
database.child("sender").child("receiver").observeSingleEvent(of: .value, with: { snapshot in
Reads the entire sender/receiver node from your database, which contains one or more child nodes with auto-generated keys, and then properties under each of those child nodes.
When you do:
value = snapshot.value as? [String: Any]
This sets value to be a dictionary/map with the top-level key(s) being the childByAutoId. When you then access value["-MrdAxlUKHvJWjtSQe7X"] you get a map/dictionary with the properties of that child node.
You can also loop over the child nodes of the snapshot with something like:
for child in snapshot.children {
let snap = child as! DataSnapshot //downcast
let dict = snap.value as! [String: Any] // get properties of child node
let msg = dict["body"] as! String
}

Replacing multiple values in Firebase

Is there a way to quickly replace values in a firebase snapshot based on certain criteria. For example, I'm looking to replace all "username" with the value "xyz" where userId = userId_0001 (userId is not unique). This is my code so far:
let databaseRef = Database.database().reference().child("usernames").queryOrdered(byChild: "userId").queryEqual(toValue: "userId_0001")
databaseRef.observe(.value, with: { (snapshot) in
for childSnapshot in snapshot.children {
let username = value?["username"] as? String ?? ""
username.setValue("xyz")
})
}
There are a few issues with the code in the question and the query value in the code (userId_0001) doesn't match the value in the screen shot (userId_001)
From what I gather, you want to query firebase for nodes with a userId of userId_001 (which matches your screenshot) and for those nodes, replace the existing username value with xyz
Here's the code that will do that
func replacer() {
let databaseRef = Database.database().reference().child("usernames").queryOrdered(byChild: "userId").queryEqual(toValue: "userId_0001")
databaseRef.observe(.value, with: { snapshot in
let childSnaps = snapshot.children.allObjects as! [DataSnapshot]
for snap in childSnaps {
snap.ref.child("username").setValue("xyz")
-- or --
snap.ref.updateChildValues(["username": "xyz"])
}
})
}
I includes two options within the for loop. Only use one. The nice thing about updateChildValues is you can replace multiple values within the parent node at once if needed.

Firebase swift not retrieving all child values

I have a piece of code inside my Swift built iOS app, to retrieve all the nodes from a Firebase Realtime database. When I execute the code below I've noticed that it does not return all the child nodes.
When I query the particular nodes which are not being returned individually, at first the code returns 'nil' and then on a second attempt retrieves the nodes. (without doing any code changes in the process). Following this process, the node starts to show up in the results with the retrieve all nodes function.
Example 1: First returns nil, then on a second attempt returns the node. Which I can see from the console and definitely exists on the database.
ref?.child("transactions").child(email).child("14526452327").observeSingleEvent(of: .value, with: { (snapshot) in
// Get user value
let value = snapshot.value as? NSDictionary
print(value)
print("!!****************!!")
// ...
}) { (error) in
print(error.localizedDescription)
}
The following is being used to retrieve all child values; at first this doesn't get all the nodes, however after running the code from Example 1 (twice) it starts to return the node in question.
ref?.child("transactions").child(email).observeSingleEvent(of: .value, with: { (snapshot) in
let childrenCount = snapshot.childrenCount
var counter : Int = 0
for trans in snapshot.children.allObjects as! [DataSnapshot]
{
counter = counter + 1
self.ref?.child("transactions").child(email).child(trans.key).observeSingleEvent(of: .value, with: { (snapshot2) in
I've also checked my Firebase query and data limits and I am nowhere near the threshold for the free account. Any help is greatly appreciated.
Try this:
func getData() {
// Making a reference
let transactionRef = Database.database().reference(withPath: "transactions")
transactionRef.observeSingleEvent(of: .value, with: { (snapshot) in
// Printing the child count
print("There are \(snapshot.childrenCount) children found")
// Checking if the reference has some values
if snapshot.childrenCount > 0 {
// Go through every child
for data in snapshot.children.allObjects as! [DataSnapshot] {
if let data = data.value as? [String: Any] {
// Retrieve the data per child
// Example
let name = data["name"] as? String
let age = data["age"] as? Int
// Print the values for each child or do whatever you want
print("Name: \(name)\nAge: \(age)")
}
}
}
})
}

Dictionary Changes Index Positions with .keys -- Swift

I'm currently retrieving data from a firebase database, and storing the data in a dictionary. When I try to list the keys in the dictionary like this: snapDict?.keys the indexes of the elements aren't the same as how they are in the database.
Database.database().reference().child("\(UserData().mySchool!)/posts").observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot.childrenCount)
let snapDict = snapshot.value as? [String: Any]
print(snapshot.value!)
let names = snapDict?.keys
print(names!)
for id in names! {
self.searchNames(id: id)
self.tableView.reloadData()
}
})
This is what the elements that will be in the dictionary look like in the database:
So, you would think when they are put into the dictionary they would be printed as -LJRUC8n........-LOF6JUdm-onVuaq-zij?
snapDict?.keys
prints:
["-LOBSAv_l5_x1xnKwx3_", "-LJRUC8nPF3Vg-DDGiYQ", "-LOBLXpTs39yLZo6EnHl", "-LOF6JUdm-onVuaq-zij", "-LODhXPQi8G7MX1bSfeb", "-LJaUiEnGOcBjKsTWSCS", "-LOBLZzrLAlzkhoidnKf"]
I can't figure out the order/pattern here. Alphabetical? Any ideas why the order turns out this way?
The keys in a dictionary are by definition unordered. So when you convert the snapshot to a dictionary, any information on the order of the nodes is lost.
On top of that, you don't specify an order before reading the data.
To fix both:
Database.database().reference()
.child("\(UserData().mySchool!)/posts")
.queryOrderedByKey()
.observeSingleEvent(of: .value, with: { (snapshot) in
print(snapshot.childrenCount)
for child in snapshot.children.allObjects as! [FIRDataSnapshot] {
print(child.value)
}
})

I need help getting values out of a snapshot from firebase

My Data in Firebase looks like this:
I am retrieving the data with
var ref: DatabaseReference
ref = Database.database().reference()
ref.child("peopleReminders").child("-LBO0TMbOM0cwd5TMMiP").observe(.value) { snapshot in
for value in snapshot.children {
print(value)
}
}
This prints the following:
Snap (0) r04
Snap (1) r02
Snap (2) r01
This should be an array. What I need to do is get the values R04, R02, and R01 out of it.
You don't need a loop or enumeration to parse it into an array as Firebase supports both Array and Dictionary. You can directly cast the result into an array. Below piece of code will work:
ref.child("peopleReminders").child("-LBO0TMbOM0cwd5TMMiP").observeSingleEvent(of: DataEventType.value) { (snapshot) in
if snapshot.exists() {
let result: [String] = snapshot.value as? [String] ?? []
print(result)
}
}
Note: Always check snapshot existence it will be false if data doesn't exist for the requested reference. Use observeSingleEvent when you need to fetch the data for once if you use observe the call back will be call many times whenever there is a change in requested node so that delete, insert, update etc.
I replaced for value in snapshot.children with the following code.
let enumerator = snapshot.children
while let rest = enumerator.nextObject() as? DataSnapshot {
print(rest.value!)
}
The new output is now:
R04
R02
R01