hi I'm new to swift and i'm using firebase in my app. i want to get all the data under a child from firebase database and compare it with an already existing array to find the missing values and load them in tableview i had added the code i use to perform this and in that the for loop is called every time when new child is found and i want to perform that for loop after getting all the values from the firebase database. is there any way to perform this or is there any way to know whether the firebase had retrieved all the data. Thanks in advance
func fetchUsers()
{
ingredientMasterArr.removeAll()
refhandle1 = ref.child("ingredients").observeEventType(.ChildAdded, withBlock:
{ (snapshot) in
if let dictionary = snapshot.value as? [String : String]
{
let ingredients = IngredientsClass()
ingredients.id = dictionary["id"]
ingredients.ingredient_name = dictionary["ingredient_name"]
// ingredients.category
ingredientMasterArr.append(ingredients)
}
FilteredIngMasterArr.removeAll()
let temp = IngredientsClass()
for MasterID in ingredientMasterArr
{
if (ShopIngKeysArr .contains(MasterID.id!)){
print("if",MasterID.ingredient_name)
}
else
{
print("else",MasterID.ingredient_name)
temp.id = MasterID.id
temp.ingredient_name = MasterID.ingredient_name
FilteredIngMasterArr.append(temp)
}
}
self.tbl_ingMaster.reloadData()
})
}
Using the .Value event type instead of .ChildAdded should give you all the results at once:
refhandle1 = ref.child("ingredients").observeEventType(.Value, ...
Read the firebase documentation on retrieving data for more details.
Related
Hi I am new to Swift/Firebase and am a bit clueless as to why cities is empty after returning objects to it. I have stepped through and a new City is being created but after it does all of the City objects, cities shows as empty. What could be causing this? The idea is to retrieve the name and image (from Firebase Storage), create a new City object from them and then have an array of these objects that I can access from another class.
self.cities = documents.map { queryDocumentSnapshot-> City in
let data = queryDocumentSnapshot.data()
let cityName = data["name"] as? String ?? ""
var cityImage: UIImage = UIImage()
let httpsRef = Storage.storage().reference(forURL: (data["image"] as! String))
httpsRef.getData(maxSize: 1 * 1024 * 1024) { data, error in
if let error = error {
print("ERROR!!! \(error)")
} else {
cityImage = UIImage(data: data!)!
}
}
return City(name: cityName, image: cityImage)
}
httpsRef.getData() is asynchronous and returns immediately, before the object data is available. The callback you provide is invoked some time later, after the data is fetched. Meanwhile, your map closure goes on to return a new City object with the initial value of cityImage that you provided before the call to getData(). Your code will need to be rewritten to account for the asynchronous nature of getData(), possibly executing in multiple stages.
so this is an image of my JSON tree:
my JSON TREE
Question:
I wanted to know how can I check if the username, let's say, sean exists in the usernames. I currently have no idea on how to implement this.
What I've tried:
The key of usernames child is "theUsernameOf-userUID", and that causes the problem as userUID is dynamic and different from each user (from firebase auth), therefore I can't use:
.queryOrderedByChild("theUsernameOf-userUID").queryEqual(toValue: self.usernameTextBox.text!)
The key of usernames child can't be static like theUsername as it would only be able to have 1 value / not able to generate more node.
Thank you so much, sorry if I didn't explain clearly enough.
I would like to modify your DB structure as current one is not the correct to perform this query.
It should be like below:
Always use auto incremented keys for queries. Here usernames -> autoGeneratedKey -> yourData (Dictionary - Key-Value pair) Now you can easily check the existence of any key.
let ref = defaultDB.reference.child("usernames")
ref.queryOrdered(byChild: "username").queryEqual(toValue: "sean").observeSingleEvent(of: DataEventType.value) { (snapshot) in
if snapshot.exists() {
print("exists")
}
else {
print("doesn't exist")
}
}
Output: exists
This is the correct way to do so. Just checking for snapshot.exists() will do the job for you.
When you observe any reference in firebase, you get a DataSnapshot in return. The snapshot has a children enumerator property on which you can enumerate each child. Each of the child will be another DataSnapshot. Now, each snapshot has key and value. You want the user name? It's in the value property:
let databaseRef = Database.database().reference(withPath: "usernames")
databaseRef.observe(.value) { (snapshot) in
snapshot.children.forEach({ (child) in
if let child = child as? DataSnapshot, let value = child.value {
print(value) //"Sean", "Yuh"
// here you can check for your desired user
}
})
}
Here is how you can do it
Set the database reference to the usernames node. For example db.ref.child("usernames")
Now parse the snapshot using for loop
let usernames = snapshot.value as! NSDictionary
Now the for loop
for username in usernames{
if username.value == "Sean"{
// do whatever you want here
}
}
You could also:
Make a firebase call to usernames and make that:
let usernames = snapshot.value as? [String: AnyObject],
then all you have to do is something like
if let keyExists = usernames[YOURUSERNAMECHECKSTRING] {
//It's true
}
Just another way of looking at it.
Try This code will Help you you dont need to change your firebase structure
In Swift
Database.database().reference(withPath: "users").queryOrdered(byChild: "usernames").queryEqual(toValue: "yourUserName").observe(.value)
{ (snapshot:DataSnapshot) in
if snapshot.valueInExportFormat() is NSDictionary
{
// User is exits
}
else
{
}
}
In Objective c
[[[[[FIRDatabase database] referenceWithPath:#"users"] queryOrderedByChild:#"usernames"] queryEqualToValue:#"your User Name"] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot)
{
if ([snapshot.valueInExportFormat isKindOfClass:[NSDictionary class]])
{
// User is exits
}
else
{
}
}];
I'm using Firebase. In my app, I get a child value by passing in a bottleID and get the details for that value from the snapshot. I then assign the details to an object of MyCollection_Class and add it to an array. After getting every single bottle value, I want to sort that array using the created_at tag before reloading the table view. Please advise me on how to sort the array of objects by a specific instance variable.
let Collection = MyCollection_Class()
FireBaseConstants.AUCTIONS_REF.child(bottleID).observeSingleEvent(of: .value, with: { (snap) in
if !(snap.value is NSNull) {
Collection.id = bottle_dict["id"] as? String
Collection.item_number = bottle_dict["item_number"] as? Int
Collection.created_at = bottle_dict["created_at"] as? String
if !(self.MyCollectionsIDArr.contains(Collection.id! as String)) {
self.MyCollectionsArr.append(Collection)
self.MyCollectionsIDArr.append(Collection.id!)
// I want to sort the MyCollectionsArr using created_at here
self.tbl_Latest.reloadData()
}
}
})
You can just retrieve the data already sorted from Firebase by using
queryOrderedByChild.
An example would be:
ref.child(bottleID).queryOrderedByChild("created_at").queryEqualToValue(0).observe SingleEventOfType(.Value, withBlock: { snap in
print("snap \(snap)")
expectation.fulfill()
})
So I am currently working on a clone like snapchat and I am sending pull requests to the server, but as for downloading, it is not going so well. I created a reference to the database that looks like this,
var recievers: FIRDatabaseReference{
return mainRef.child("pullRequests")
}
and then I have a viewController that parses the data (which I know isn't the best way to go about this but I'm just trying to get it working right now) and in there I have this
DataService.instance.recievers.observeSingleEvent(of: .value) {(recipients: FIRDataSnapshot) in
if let recipient = recipients.value as? Dictionary<String,AnyObject>{
var index = 0;
for(key,value) in recipient{
index = index+1
if let dict = value as? Dictionary<String,AnyObject>{
if let reciever = dict["recipents"] as? Dictionary<String,AnyObject>{
if let num = reciever["\(index)"] as? String{
let uid = num
recipientsArr.append(uid)
}
}
}
}
}
}
for i in 0...recipientsArr.count{
print(i)
}
I'm not getting any compiling errors but it is also not adding anything into the recipientsArr, can anyone help guide me in the right direction?
My Firebase looks like this:
You're not decoding the snapshot properly. Its unclear from your question what is the value event you want to observe - is it just a new recipient that was added? the whole pullRequest?
In any case you're observing the pullRequest reference and therefore in order to decode the snapshot:
if let pullRequest = recipients.value as? Dictionary<String,AnyObject>{
if let recipientsList = pullRequest["recipents"] as? Dictionary<String,AnyObject>{
for (_, value) in recipientsList {
if let uid = value as? String{
recipientsArr.append(uid)
}
}
}
}
The problem is that you are using the method observeSingleEvent to update the value in the database, when this method is only used to recieve data from the database, not updated. In other words, it read-only.
The way to update record in a firebase database works different than the read methods. You can use both methods setValue and updateChildValues to perform updates. They both work on a database reference.
To use the setValue method, you should do something like this. I'll assume that you already have a pullRequests object that you previously created from the information you fetched from the database and have it in a variable:
let previousRecipents = pullRequests.recipents
let allRecipents = previousRecipents.append(newRecipent) // Assuming preivousRecipents is an array and you have the new Recipent
recievers.child("recipents").setValue(allRecipents)
To use the updateChildValues, it works very similar.
let previousRecipents = pullRequests.recipents
let allRecipents = previousRecipents.append(newRecipent) // Assuming preivousRecipents is an array and you have the new Recipent
let parametersToUpdate = ["recipents": allRecipents]
recievers.updateChildValues(parametersToUpdate)
For further information on how to update, check the following link:
https://firebase.google.com/docs/database/ios/save-data
Hope it helps!
I want to be able to do some custom filtering on the Datasnapshot I get back. I don't think I can create a complex query to accomplish the result I want.
Is this possible to do and if so, what is the best way of parsing the snapshot?
EDIT:
I am using SwiftyJSON and this is how I ended up parsing it:
standbyRef.observeSingleEventOfType(.Value, withBlock: { snapshot in
// do some stuff once
println(snapshot.value)
self.parseJson(snapshot.value as NSDictionary)
})
func parseJson(var snapshot:NSDictionary!){
let json = JSON(snapshot)
for (key: String, subJson: JSON) in json {
// key to standby users
println(key)
// one object at a time
println(subJson)
}
}
Firebase accepts all the data in JSON format only. When you get a Datasnapshot of any perticular node of Firebase, you get the complete data below that node, which is in all a JSON only.
Once you get the Datasnapshot JSON you can parse it using any JSON library, depending on the platform you use.
You can refer here Datasnapshot Methods for more info.
Without any additional library, you can also do something like that:
if let email = snapshot.value["email"] as? String {
user.email = email
}
Or if you want to iterate over all values:
let enumerator = snapshot.children
while let child = enumerator.nextObject() as? FDataSnapshot {
println(child.key)
println(child.value)
}