I was trying to retrieve data from firebase. I can retrieve data from a single child. But how can I retrieve data from many child?
I tried this way
func fatchSchdual(){
ref.child("Products").child(productdetailes[myIndex].userId!).child("Schedule").child("0").observeSingleEvent(of: .value) { (snapshot) in
if snapshot.childrenCount > 0{
for Schdu in snapshot.children.allObjects as! [DataSnapshot]{
let schdual = Schdu.value as? [String: AnyObject]
let startTime = schdual?["start"]
let endTime = schdual?["end"]
if let StartTime = startTime{
self.publishTime.text = StartTime as? String
}
}
}
}
}
but I didn't get any data.
func fatchFacilities(){
ref.child("Products").child(productdetailes[myIndex].userId!).child("Facility").observeSingleEvent(of: .value) { snapshot in
for child in snapshot.children {
if let value = (child as! DataSnapshot).value as? [String : Any] {
let name = value["name"] as? String
let unit = value["unit"] as? String
let facility = Facility(name: name, unit: unit)
facilities.append(facility)
}
}
}
}
ref = Database.database().reference()
ref.child("Clubs").observe(.value, with: { (snapshot : DataSnapshot) in
print("clubs: \(snapshot)")
if let childSnapshot = snapshot.value as? [String : AnyObject] {
print("myClubs: \(childSnapshot)")
From this point, i am unable to get the "name" and "bannerImage" to load into my tableView
if let clubName = childSnapshot["name"] as? String, let banner = childSnapshot["bannerImage"] as? String {
print(clubName)
print(banner)
let club = Club(name: clubName, image: banner)
print("new club success: \(club)")
self.nightClubs.append(club)
self.tableView.reloadData()
}
Use this:-
ref = Database.database().reference()
ref.child("Clubs").observe(.value, with: { (snapshot) in
print("clubs: \(snapshot)")
if(snapshot.exists()) {
let array:NSArray = snapshot.children.allObjects as NSArray
for obj in array {
let snapshot:FIRDataSnapshot = obj as! FIRDataSnapshot
if let childSnapshot = snapshot.value as? [String : AnyObject] {
print("myClubs: \(childSnapshot)")
if let clubName = childSnapshot["name"] as? String, let banner = childSnapshot["bannerImage"] as? String {
print(clubName)
print(banner)
let club = Club(name: clubName, image: banner)
print("new club success: \(club)")
self.nightClubs.append(club)
}
}
}
self.tableView.reloadData()
}
}
does anyone have a suggestion how to get rid off the user obligation when posting new element to the Firebase database? I would like to create open feed but this is only for one particular user.
Thank you!
The function starts like:
func fetchPosts(){
let ref = Database.database().reference()
ref.child("users").queryOrderedByKey().observeSingleEvent(of: .value, with: { snapshot inlet users = snapshot.value as! [String : AnyObject]
The main problem I see in this:
for (_,value) in users {
if let uid = value["uid"] as? String {
if uid == Auth.auth().currentUser?.uid {
if let followingUsers = value["following"] as? [String : String]{
for (_,user) in followingUsers{
self.following.append(user)
}
}
self.following.append(Auth.auth().currentUser!.uid)
ref.child("posts").queryOrderedByKey().observeSingleEvent(of: .value, with: { (snap) in
let postsSnap = snap.value as! [String : AnyObject]
for (_,post) in postsSnap {
if let userID = post["userID"] as? String {
for each in self.following {
if each == userID {
I guess this would be the same:
let posst = Post()
if let author = post["author"] as? String, let likes = post["likes"] as? Int, let pathToImage = post["pathToImage"] as? String, let postID = post["postID"] as? String {
posst.author = author
posst.likes = likes
posst.pathToImage = pathToImage
posst.postID = postID
posst.userID = userID
if let people = post["peopleWhoLike"] as? [String : AnyObject] {
for (_,person) in people {
posst.peopleWhoLike.append(person as! String)
}
}
self.posts.append(posst)
}
}
}
self.collectionview.reloadData()
}
}
})
}
}
}
})}
OK so if I am understanding your question correctly you want anyone signed in to be able to see all the posts not just the posts of the users they are following.
If this is in fact the case then you do not need to check who the user is following. You just want to load all of the posts. Change
for (_,post) in postsSnap {
if let userID = post["userID"] as? String {
for each in self.following {
if each == userID {
To
self.ref.child("posts").queryOrderedByKey().observeSingleEvent(of: .value, with: { snap in
if let postsSnap = snap.value as? [String: AnyObject] {
for(_, post) in postsSnap {
if let userID = post["userID"] as? String {
for each in self.following {
if each == userID {
let posst = Post()
if let author = post["author"] as? String, let likes = post["likes"] as? Int, let pathToImage = post["pathToImage"] as? String, let postID = post["postID"] as? String, let postDescription = post["postDescription"] as? String, let timestamp = post["timestamp"] as? Double, let category = post["category"] as? String, let group = post["group"] as? Int {
posst.author = author
posst.likes = likes
posst.pathToImage = pathToImage
posst.postID = postID
posst.userID = userID
posst.fancyPostDescription = self.createAttributedString(author: author, postText: postDescription)
posst.postDescription = author + ": " + postDescription
posst.timestamp = timestamp
posst.group = group
posst.category = category
posst.userWhoPostedLabel = self.createAttributedPostLabel(username: author, table: group, category: category)
if let people = post["peopleWhoLike"] as? [String: AnyObject] {
for(_, person) in people {
posst.peopleWhoLike.append(person as! String)
}
}
self.posts.append(posst)
} // end if let
}
}
self.tableView.reloadData()
}
}
}
})
ref.removeAllObservers()
If you want anyone to be able to read / write to your database you have to update the rules in the Firebase console. You do this by clicking on database then rules. The default rules look like this:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
Change them to
{
"rules": {
".read": "true",
".write": "true"
}
}
I looked at the video you're following and he make's a lot of mistakes. Really when you request data from Firebase you should be paging i.e. loading a set number of posts and then loading more based on the scroll position.
I have this function that it will be triggered every time a user changes his picture, and will get the profilePictureUrl of the current user and update all posts matching the currentUser in the database. Works fine! Is doing the job. How do I update the indexPath of those particular cells? Right now my cells images are empty after the update.
var pathToPictures = [Pictures]()
func updateAllImagesOfCurrentUserInDatabase() {
//refrences
let ref = FIRDatabase.database().reference()
let uid = FIRAuth.auth()?.currentUser?.uid
//match the user ID value stored into posts with current userID and get all the posts of the user
let update = ref.child("posts").queryOrdered(byChild: "userID").queryEqual(toValue: uid)
update.observe(FIRDataEventType.value, with: { (snapshot) in
self.pathToPictures.removeAll()
if snapshot.value as? [String : AnyObject] != nil {
let results = snapshot.value as! [String : AnyObject]
for (_, value) in results {
let pathToPostPicture = Pictures()
if let pathToImage = value["pathToImage"] as? String , let postID = value["postID"] as? String {
pathToPostPicture.postImageUrl = pathToImage
pathToPostPicture.postID = postID
self.pathToPictures.append(pathToPostPicture)
print("Image and POST ID: \(pathToPostPicture.postImageUrl!)")
print("Post ID is : \(postID)")
if FIRAuth.auth()?.currentUser?.uid == uid {
ref.child("Users_Details").child(uid!).child("profileImageUrl").observeSingleEvent(of: .value, with: { (userSnapshot) in
print(userSnapshot)
let userIMageUrl = userSnapshot.value as! String
pathToPostPicture.postImageUrl = userIMageUrl
self.pathToPictures.append(pathToPostPicture)
print("This is the image path:" + userIMageUrl + String(self.pathToPictures.count))
// Update the Database
let postIDCount = pathToPostPicture.postID!
let updatedUserData = ["posts/\(postIDCount)/pathToImage": pathToPostPicture.postImageUrl!]
print("This is THE DATA:" , updatedUserData)
ref.updateChildValues(updatedUserData as Any as! [AnyHashable : Any])
})
}
print(self.pathToPictures.count)
}
}
} else {
print("snapshot is nill - add some data")
}
self.collectionView?.reloadData()
})
}
I'm trying to make a fetch from my database to populate a collection view, in order of newest at the top, down to oldest. I tried using snap.children.allObjects.reversed(), but my app crashes upon loading. Here's the full fetch function:
func fetchPosts() {
let ref = FIRDatabase.database().reference()
ref.child("users").queryOrderedByKey().observe(.value, with: { snapshot in
let users = snapshot.value as! [String : AnyObject]
for (_, value) in users {
if let uid = value["uid"] as? String {
if uid == FIRAuth.auth()?.currentUser?.uid {
if let followingUsers = value["following"] as? [String : String] {
for (_, user) in followingUsers {
self.following.append(user)
}
}
self.following.append(FIRAuth.auth()!.currentUser!.uid)
ref.child("posts").queryOrderedByKey().observeSingleEvent(of: .value, with: { (snap) in
for postSnapshot in snap.children.allObjects.reversed() as! [FIRDataSnapshot] {
let value = postSnapshot.value as! [String : AnyObject]
if let userID = value["userID"] as? String {
for each in self.following {
if each == userID {
let posst = Post()
if let poster = value["poster"] as? String, let likes = value["likes"] as? Int, let pathToImage = value["pathToImage"] as? String, let postID = value["postID"] as? String {
posst.poster = poster
posst.likes = likes
posst.pathToImage = pathToImage
posst.postID = postID
posst.userID = userID
if let people = value["peopleWhoLike"] as? [String : AnyObject] {
for (_, person) in people {
posst.peopleWhoLike.append(person as! String)
}
}
posts.append(posst)
}
}
}
self.collectionView.reloadData()
}
}
})
ref.removeAllObservers()
}
}
}
})
}
The error is EXC_BAD_INSTRUCTION (code=EXC_1386_INVOP, subcode=0x0), with the warning Cast from 'ReversedRandomAccessCollection<[Any]>' (aka 'ReversedRandomAccessCollection>') to unrelated type '[FIRDataSnapshot]' always fails.
Is .reversed not the way to go about this? As it is, my code without .reversed loads the posts in order from oldest at the top, down to the newest at the bottom. How can I switch it around?
EDIT: Firebase snippet of posts:
"posts" : {
"-KfWzWv8rP38bUreDupj" : {
"likes" : 1,
"pathToImage" : "https://firebasestorage.googleapis.com/v0/b/cloudcamerattt.appspot.com/o/posts%2F1JSgke8QqFds4CxF2Z4MhuzbRoW2%2F-KfWzWv8rP38bUreDupj.jpg?alt=media&token=fef86bea-1ae2-4e1e-82fa-6209bc281a5e",
"peopleWhoLike" : {
"-KfX29jTcwaQDpkdIVX8" : "yI6NokUl2mTa7Uah4SgtAiulTJH2",
"-KfXQJBRemZUCI2ieT94" : "MpnGvQj7ZOdz12zKD0bTeX1kp0B3"
},
"postID" : "-KfWzWv8rP38bUreDupj",
"poster" : "Harry Potter",
"userID" : "1JSgke8QqFds4CxF2Z4MhuzbRoW2"
},
EDIT 2: Adding a timestamp
Added var timestamp: Int! to my Post object, then add it into my upload function:
func uploadToFirebase() {
AppDelegate.instance().showActivityIndicator()
let uid = FIRAuth.auth()!.currentUser!.uid
let ref = FIRDatabase.database().reference()
let storage = FIRStorage.storage().reference(forURL: "gs://cloudcamerattt.appspot.com")
let key = ref.child("posts").childByAutoId().key
let imageRef = storage.child("posts").child(uid).child("\(key).jpg")
let data = UIImageJPEGRepresentation(self.previewImage.image!, 0.6)
var Timestamp: TimeInterval {
return NSDate().timeIntervalSince1970 * 1000
}
let uploadTask = imageRef.put(data!, metadata: nil) { (metadata, error) in
if error != nil {
print(error!.localizedDescription)
AppDelegate.instance().dismissActivityIndicator()
return
}
imageRef.downloadURL(completion: { (url, error) in
if let url = url {
let feed = ["userID" : uid,
"pathToImage" : url.absoluteString,
"likes" : 0,
"poster" : FIRAuth.auth()!.currentUser!.displayName!,
"postID" : key,
"timestamp" : (0-Timestamp)] as [String : Any]
let postFeed = ["\(key)" : feed]
ref.child("posts").updateChildValues(postFeed)
AppDelegate.instance().dismissActivityIndicator()
let feedController = self.storyboard?.instantiateViewController(withIdentifier: "feedVC") as! FeedViewController
feedController.navigationItem.setHidesBackButton(true, animated: false)
self.tabBarController?.selectedIndex = 0
}
})
}
uploadTask.resume()
}
Then add it into my fetch:
let posst = Post()
if let poster = value["poster"] as? String, let likes = value["likes"] as? Int, let pathToImage = value["pathToImage"] as? String, let postID = value["postID"] as? String, let timestamp = value["timestamp"] as? Int {
posst.poster = poster
posst.likes = likes
posst.pathToImage = pathToImage
posst.postID = postID
posst.userID = userID
posst.timestamp = timestamp
Updated fetch function (results in crash Could not cast value of type 'FIRDataSnapshot' (0x10584eee8) to 'NSArray' (0x107b43dd8).):
func fetchPosts() {
let ref = FIRDatabase.database().reference()
ref.child("users").queryOrderedByKey().observe(.value, with: { snapshot in
let users = snapshot.value as! [String : AnyObject]
for (_, value) in users {
if let uid = value["uid"] as? String {
if uid == FIRAuth.auth()?.currentUser?.uid {
if let followingUsers = value["following"] as? [String : String] {
for (_, user) in followingUsers {
self.following.append(user)
}
}
self.following.append(FIRAuth.auth()!.currentUser!.uid)
for child in snapshot.children.reversed() {
let snap = child as! [FIRDataSnapshot]
ref.child("posts").queryOrdered(byChild: "timestamp").observeSingleEvent(of: .value, with: { (snap) in
if let userID = value["userID"] as? String {
for each in self.following {
if each == userID {
let posst = Post()
if let poster = value["poster"] as? String, let likes = value["likes"] as? Int, let pathToImage = value["pathToImage"] as? String, let postID = value["postID"] as? String, let timestamp = value["timestamp"] as? Int {
posst.poster = poster
posst.likes = likes
posst.pathToImage = pathToImage
posst.postID = postID
posst.userID = userID
posst.timestamp = timestamp
if let people = value["peopleWhoLike"] as? [String : AnyObject] {
for (_, person) in people {
posst.peopleWhoLike.append(person as! String)
}
}
posts.append(posst)
}
}
}
self.collectionView.reloadData()
}
})
}
ref.removeAllObservers()
}
}
}
})
}
Try
for child in snapshot.children.reversed() {
let snap = child as! FIRDataSnapshot
print(snap)
}
You are ordering by key which will load the oldest to the newest. If you want to reverse the order, and let Firebase do the heavy lifting, use a technique for reverse chronological order posted here
In Firebase, how can I query the most recent 10 child nodes?
Then it's easy to do a reverse query...
"posts" : {
"-KfWzWv8rP38bUreDupj" : {
"likes" : 1,
"pathToImage" : "https:/...",
"peopleWhoLike" : {
"-KfX29jTcwaQDpkdIVX8" : "yI6NokUl2mTa7Uah4SgtAiulTJH2",
"-KfXQJBRemZUCI2ieT94" : "MpnGvQj7ZOdz12zKD0bTeX1kp0B3"
},
"postID" : "-KfWzWv8rP38bUreDupj",
"poster" : "Harry Potter",
"timestamp" : -1.46081635550362E12, //Just add this child
"userID" : "1JSgke8QqFds4CxF2Z4MhuzbRoW2"
},
and then
ref.child("posts").queryOrdered(byChild: "timestamp").observe(...
Also, the duplicate postID is probably not needed as a child as it's the key to the post as well.
You are correct that you need to cast something somewhere, because Swift only knows that we started with an array of Any. The problem is that you are casting the wrong thing in the wrong place. Cast postSnapshot at the start of the inside of the for loop.
The way to figure out this sort of thing is to make a simplified playground example. You are doing the equivalent of this:
let arr : [Any] = [1,2,3]
for i in arr.reversed() as! [Int] { // crash
}
What we know in that example, however, is not something about arr.reversed(); it is that i is an Int. This is fine:
let arr : [Any] = [1,2,3]
for i in arr.reversed() {
if let i = i as? Int {
// now it is safe to use `i`
}
}
Your case is parallel. At the start of the for loop, you need to cast postSnapshot to a FIRDataSnapshot. Now you can proceed.