Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
So I have the following code to retreive data from my firebase database:
ref = Database.database().reference().child("data").child("someData")
ref.observeSingleEvent(of: .value) { (snapshot) in
for child in snapshot.children {
let someSnap = child as! DataSnapshot
self.someArray.append(someSnap.key)
self.collectionView?.reloadData()
}
This code succesfully appends the 4 string elements i have in my database to the array in my viewcontroller class, however it does so over and over again. The array keeps growing with hundreds of strings of the same 4 items over and over. How can I get only the 4 items I want?
It seems that you call the function many times , so make sure to clear it
self.someArray.removeAll()
for child in snapshot.children {
let someSnap = child as! DataSnapshot
self.someArray.append(someSnap.key)
}
self.collectionView?.reloadData()
As from your question, you are calling function many times, when you call function again remove all elements from array or clear array and reload your collection view so it does not add same items again. As updated your code:
ref = Database.database().reference().child("data").child("someData")
ref.observeSingleEvent(of: .value) { (snapshot) in
self.someArray.removeAll()
for child in snapshot.children {
let someSnap = child as! DataSnapshot
self.someArray.append(someSnap.key)
}
self.collectionView?.reloadData()
}
Since I don't have access to the database I'd suggest you use the debugger over the for loop and trace it step by step and checking for the values in each iteration to see what exactly you're appending to the array
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I am trying to fetch users form my Firebase database, display their names on the UITableView and be able to search through them. For some reason, I am seeing two errors on this function to fetch users.
ERROR: Value of type 'User' has no member 'append' at the line 'self.users.append(user)'
ERROR: No 'dispatch_get_main_queue' candidates produce the expected contextual result type '(DispatchQueue, () -> Void)' at the line 'dispatch_async(dispatch_get_main_queue)'
If you know any way to fix this please let me know. I've been stuck on this for a while now and can't seem to get the users to display. Thanks.
func fetchUser() {
Database.database().reference().child("users").observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User()
//will crash if your class properties don't exactly match up with firebase dictionary keys
user.setValuesForKeys(dictionary)
self.users.append(user)
//this will crash because of background thread, so use dispatch async to fix
dispatch_async(dispatch_get_main_queue)
self.tableView.reloadData()
print(user.name!, user.email!)
Second error is because that's not a proper syntax for running something on main thread. Should be
DispatchQueue.main.async {
self.tableView.reloadData()
}
As for the first error, I can only speculate (since you didn't provide how self.users is defined. But I suspect you defined it as var users: User, instead of array. So make sure you have:
var users: [User]
or with initialization:
var users = [User]()
I want to retrieve data on with this value 7hmpcTuCAYQAYRqP7RNmnegSd9r2
But i'm getting all four objects in snapshot. I want to get parent key values which contain this key
7hmpcTuCAYQAYRqP7RNmnegSd9r2
Need to get blue mark keys.
Here is my code
let ref = FirebaseManager.refs.databaseRoot.child("new_ChatListMembers")
ref.queryOrdered(byChild: (Auth.auth().currentUser?.uid)!).queryEqual(toValue: true)
ref.observeSingleEvent(of: .value) { (snapshot) in
print(snapshot)
}
This code return four objects instead of two.Please help me how i can get specific data.
Thanks
You're not actually using the query that you construct in your code. To use that, it'd be something like:
let ref = FirebaseManager.refs.databaseRoot.child("new_ChatListMembers")
let query = ref.queryOrdered(byChild: (Auth.auth().currentUser?.uid)!).queryEqual(toValue: true)
query.observeSingleEvent(of: .value) { (snapshot) in
print(snapshot)
}
But this won't actually scale very well, as you'll need to define an index for each individual UID value in this structure. In short: your current data structure makes it each to find the users for a specific chat room, but it doesn't help finding the chat rooms for a specific user.
To allow the latter, you'll want to add an extra structure in your data:
user_chats: {
"$uid": {
"$chatid": true
}
}
So this is pretty much the inverse of what you have already, which is why this is often called an inverse index.
For more on this, and another example, see my answer here: Firebase query if child of child contains a value
This question isn't about how to loop over children, it's about looping over children in different ways to save costs
My database is:
-someRef
-someUserId // say this ref has 10000 children
-uid1: someVal
-uid2: someVal
-uid3: someVal
...
-uid7989: someVal
...
-uid10000: someVal
Following this answer I can loop over children like so:
var lookForThisUserId = "uid7989"
someRef?.observeSingleEvent(of: .value, with: { (snapshot) in
for child in snapshot.children {
let snap = child as! DataSnapshot
if snap.key == self.lookForThisUserId {
// user found
break
}
}
})
But I asked this question the other day and initially picked this answer which turned out to be an inefficient way of trying to do what I wanted done. In the comments #Jay said
"There's an accepted answer but here's the issue. What you're
essentially trying to do is track the number of children in a node. As
is, that's done by reading in the entire node (which could be
thousands of votes) and using .childrenCount. That will result in
reading in a LOT of unnecessary data and driving up costs"
So it got me to thinking, is there any difference in costs between the loop code I added above and this code below:
var lookForThisUserId = "uid7989"
someRef?.child(lookForThisUserId).observeSingleEvent(of: .value, with: { (snapshot) in
if !snapshot.exists() {
// this user isn't in here
}
// user found
})
I'm making an app where users can buy and sell tickets. Users are able to create a new ticket and it successfully uploads to firebase however a reference to the ticket ID is stored in the user data which references the ticket id in the ticket data. The structure of the database is below:
DATABASE
USERS
TICKETS
TICKETS
TICKET INFO
USER
USER INFO AND TICKET ID OF TICKETS THEY ARE SELLING
My problem is that the first time I load the tickets from the selling tickets it's fine. However when the user adds a new ticket that they are selling, the table view loads everything twice.
override func viewWillAppear(_ animated: Bool) {
self.tickets = []
DataService.ds.REF_USER_CURRENT.child("selling").observe(.value, with: { (snapshot) in //HERE WE REFERNCE OUR SINGELTON CLASS AND OBSERVE CHAMGE TO THE POSTS OBJECT
self.tickets = [] //WE CLEAR THE POSTS ARRAY BEFORE WE START MANIPULATION TO MAKE SURE THAT WE DONT REPEAT CELLS
if let snapshot = snapshot.children.allObjects as? [DataSnapshot]{
print("ADAM: \(snapshot)")//CHECKING THAT THE OBJECTS EXIST AS AN ARRAY OF DATA SNAPSHOTS
for snap in snapshot {
DataService.ds.REF_TICKETS.child(snap.key).observe(.value, with: { (snapshot) in
if let ticketDict = snapshot.value as? Dictionary<String, AnyObject>{
let ticket = Ticket(ticketID: snap.key, ticketData: ticketDict)
self.self.tickets.append(ticket)
}
self.sell_ticketsTableView.reloadData()
})
}
}
//self.sell_ticketsTableView.reloadData()
self.tickets = []//RELAOD THE DATA
})
}
I'm not quite sure where I have gone wrong.
Please change your code to this. I have added the part where you clear your array
override func viewWillAppear(_ animated: Bool) {
self.removeAll() // This is how you clear your array
DataService.ds.REF_USER_CURRENT.child("selling").observe(.value, with: { (snapshot) in //HERE WE REFERNCE OUR SINGELTON CLASS AND OBSERVE CHAMGE TO THE POSTS OBJECT
self.tickets = [] //WE CLEAR THE POSTS ARRAY BEFORE WE START MANIPULATION TO MAKE SURE THAT WE DONT REPEAT CELLS
if let snapshot = snapshot.children.allObjects as? [DataSnapshot]{
print("ADAM: \(snapshot)")//CHECKING THAT THE OBJECTS EXIST AS AN ARRAY OF DATA SNAPSHOTS
for snap in snapshot {
DataService.ds.REF_TICKETS.child(snap.key).observe(.value, with: { (snapshot) in
if let ticketDict = snapshot.value as? Dictionary<String, AnyObject>{
let ticket = Ticket(ticketID: snap.key, ticketData: ticketDict)
self.tickets.append(ticket)
}
self.sell_ticketsTableView.reloadData()
})
}
}
//self.sell_ticketsTableView.reloadData()
})
}
You are observing the value of what a user is selling, which means every time they add something to this list, your listener will trigger and give you the new value of users/$uid/selling in its entirety.
This is why you are seeing double when the user adds another ticket; the listener is triggered and you append each ticket to the array again. You can get around this by checking if the ticket is already in the array before you append it however, your current implementation can be improved.
Instead of using observe(.value, you should use .childAdded. The listener will trigger every time a new child is added and only give you that specific child snapshot.
The listener will initially trigger for each child at that reference and you can append them to the array individually. However, once all the children have been loaded, the next child to be added will trigger this listener, which you can append to the array.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I'm trying to fetch data in a specific data such in age_range inside the 'min' which equal to 21
although 'total' inside 'summary' that is inside friends.
i only success fetching normal data such as name and gender ....
your help would be much appreciable
If I understand your question correctly you want to retrieve data from the child of a child.
ref?.child("users").child(uid).child("youCanAddAsManyOfTheseAsYouWishToAccessChildrenOfChildren").observeSingleEvent(of: .value, with: { (snapshot) in
//you can either access children in the line above or by:
snapshot.childSnapshot(forPath: "childName").value
})
If this is not the answer to your question just comment below.
edit: Here is an exact example for you.
ref?.child("users").child(uid).child("FB result").child("age_range").child("min").observeSingleEvent(of: .value, with: { (snapshot) in
//you can either access children in the line above or by:
print(snapshot.value)
})
Swift 3 & Xcode 8.3.2
I hope this code will solve your problem
// Create constant of baseURL (Make your life easier)
let baseURl = Database.database().reference()
// create reference that u want to fetch
let refToFetch = baseURl.child("users").child("uid").child("FB result").child("age_range")
// fetch the value
refToFetch.observeSingleEvent(of: .value, with: { (snapshot) in
// do something with value for key "min"
print(snapshot.value(forKey: "min") ?? "no value")
if let value: Int = snapshot.value(forKey: "min") as? Int {
// You got the value
print("value of min is: \(value)")
}
}) { (error) in
print(error, "Failed to fetch value")
}