How do I filter data from my Firebase Database? - swift

How do I change the fetchAllPosts function in my networking file and in the homeviewController so that I only get posts from the database that match the UID of the user I’m following with the post.UID, so my feed is filled with posts of users I follow?
Here is the reference showing how I make a new follower in the database:
let followingRef = "following/" + (self.loggedInUserData?["uid"] as! String) + "/" + (self.otherUser?["uid"] as! String)
Here is the post structure in the Firebase database
posts
-Ke4gQKIbow10WdLYMTL (generated key)
postDate:
postId:
postPicUrl:
postText:
postTit:
type:
uid: looking to match this
Here is the current fetchAllPosts function in the networking file
func fetchAllPosts(completion: #escaping ([Post])->()) {
let postRef = self.dataBaseRef.child("posts")
postRef.observe(.value, with: { (posts) in
var resultsArray = [Post]()
for post in posts.children {
let post = Post(snapshot: post as! FIRDataSnapshot)
resultsArray.append(post)
}
completion(resultsArray)
}) { (error) in
print(error.localizedDescription)
}
}
here is the fetchAllPosts function in the homeViewController
private func fetchAllPosts(){
authService.fetchAllPosts {(posts) in
self.postsArray = posts
self.postsArray.sort(by: { (post1, post2) -> Bool in
Int(post1.postDate) > Int(post2.postDate)
})
self.tableView.reloadData()
}
}
Here is my post structure in my swift file:
struct Post {
var username: String!
var uid: String!
var postId: String!
var type: String
var postText: String
var postTit: String
var postPicUrl: String!
var postDate: NSNumber!
var ref: FIRDatabaseReference!
var key: String = ""
init(postId: String,postText: String, postTit:String, postDate:NSNumber, postPicUrl: String?, type:String, uid: String, key: String = ""){
self.postText = postText
self.postTit = postTit
self.postPicUrl = postPicUrl
self.type = type
self.uid = uid
self.postDate = postDate
self.postId = postId
}
init(snapshot: FIRDataSnapshot){
self.ref = snapshot.ref
self.key = snapshot.key
self.postId = (snapshot.value! as! NSDictionary)["postId"] as! String
self.type = (snapshot.value! as! NSDictionary)["type"] as! String
self.postPicUrl = (snapshot.value! as! NSDictionary)["postPicUrl"] as! String
self.postDate = (snapshot.value! as! NSDictionary)["postDate"] as! NSNumber
self.postTit = (snapshot.value! as! NSDictionary)["postTit"] as! String
self.uid = (snapshot.value! as! NSDictionary)["uid"] as! String
self.postText = (snapshot.value! as! NSDictionary)["postText"] as! String
}
func toAnyObject() -> [String: Any] {
return ["postId":self.postId,"type":self.type, "postPicUrl":self.postPicUrl,"postDate":self.postDate, "postTit":self.postTit,"uid": self.uid, "postText":self.postText,]
}
}

Did you use this;
postRef.queryOrdered(byChild: "uid").queryEqual(toValue: yourUid).observe(.value, with: {
snapshot in
if let shot = snapshot {
let post = Post(snapshot: post as! FIRDataSnapshot)
}
}
This returns data you are looking for.

Related

passing string from firebase realtime database request

How can I pass the string userImage which I get from a firebase realtime database request? I can not just use return userImage. It says Unexpected non-void return value in void function. I want the userImage as result and paste it to XXXXXX.
...
func datenBankAbfrage() {
print("datenbankabfrage getriggert")
dic = [:]
for name in myFeed.myArray1[0..<myFeed.myArray1.count] {
ref = Database.database().reference().child("placeID/\(name)")
ref.observe(.value) { (snapshot) in
self.dic[name] = []
var specificNameVideos = [importComment]()
for video in snapshot.children.allObjects as! [DataSnapshot] {
let Object1 = video.value as? [String: AnyObject]
let timestampDate = NSDate(timeIntervalSince1970: Double(Object1?["userTime"] as! NSNumber)/1000)
let dateFormatter = DateFormatter()
dateFormatter.timeZone = NSTimeZone.local
dateFormatter.dateFormat = "dd.MM.YY hh:mm"
let time = dateFormatter.string(from: timestampDate as Date)
print(time + "Uhr")
let userName = Object1?["userName"]
...
let kommentarCount = Object1?["kommentarCount"]
let userID = Object1?["userID"]
//print(userID!)
ViewComments.commentIDNew = commentId as! String
func wertBerechnen(completion: #escaping (String) -> Void) {
self.ref = Database.database().reference()
self.ref.child("user/\(userID!)").observeSingleEvent (of: .value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
let userImage = value?["picture"] as? String ?? ""
completion(userImage)
})
}
wertBerechnen { userImage in
let video = importComment(
userName: userName as! String, userGroup: userGroup as! String,
userComment: userComment as! String, userTime: userTime as! String,
userLikes: userLikes as! Int, commentId: commentId as! String, placeID: placeID as! String, kommentarCount: kommentarCount as? Int, userImage: userImage)
specificNameVideos.append(video)
}
}
self.dic[name] = specificNameVideos
let tem = Array(self.dic.values).flatMap { $0 } // You can also sort allComments with userTime property
self.table = tem.sorted { $0.userTime! > $1.userTime! }
self.tableView.reloadData()
}
myFeed.myArray1 = []
}
...
You can use a completion handler to return the userImage string:
func wertBerechnen(completion: #escaping (String) -> Void) {
self.ref = Database.database().reference()
self.ref.child("user/\(userID!)").observeSingleEvent (of: .value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
let userImage = value?["picture"] as? String ?? ""
completion(userImage)
})
}
Then you can call it like this:
wertBerechnen { userImage in
let video = importComment(
userName: userName as! String, userGroup: userGroup as! String,
userComment: userComment as! String, userTime: userTime as! String,
userLikes: userLikes as! Int, commentId: commentId as! String, placeID: placeID as! String, kommentarCount: kommentarCount as? Int, userImage: userImage)
specificNameVideos.append(video)
}
self.dic[name] = specificNameVideos
let tem = Array(self.dic.values).flatMap { $0 }
self.table = tem.sorted { $0.userTime! > $1.userTime! }
self.tableView.reloadData()
}
}
You need to reload the tableView data inside the wertBerechnen completion handler:
func wertBerechnen(completion: #escaping (String) -> Void) {
self.ref = Database.database().reference()
self.ref.child("user/\(userID!)").observeSingleEvent (of: .value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
let userImage = value?["picture"] as? String ?? ""
completion(userImage)
})
}
Then you can call it like this:
wertBerechnen { userImage in
let video = importComment(
userName: userName as! String, userGroup: userGroup as! String,
userComment: userComment as! String, userTime: userTime as! String,
userLikes: userLikes as! Int, commentId: commentId as! String, placeID: placeID as! String, kommentarCount: kommentarCount as? Int, userImage: userImage)
specificNameVideos.append(video)
self.tableView.reloadData()
}
self.dic[name] = specificNameVideos
let tem = Array(self.dic.values).flatMap { $0 }
self.table = tem.sorted { $0.userTime! > $1.userTime! }
}
}

Unpacking Firestore array with objects to a model in swift

I have a project in swift with Firestore for the database. My firestore dataset of a user looks like this. User details with an array that contains objects.
I have a function that gets the specifick user with all firestore data:
func fetchUser(){
db.collection("users").document(currentUser!.uid)
.getDocument { (snapshot, error ) in
do {
if let document = snapshot {
let id = document.documentID
let firstName = document.get("firstName") as? String ?? ""
let secondName = document.get("secondName") as? String ?? ""
let imageUrl = document.get("imageUrl") as? String ?? ""
let joinedDate = document.get("joinedDate") as? String ?? ""
let coins = document.get("coins") as? Int ?? 0
let challenges = document.get("activeChallenges") as? [Challenge] ?? []
let imageLink = URL(string: imageUrl)
let imageData = try? Data(contentsOf: imageLink!)
let image = UIImage(data: imageData!) as UIImage?
let arrayWithNoOptionals = document.get("activeChallenges").flatMap { $0 }
print("array without opt", arrayWithNoOptionals)
self.user = Account(id: id, firstName: firstName, secondName: secondName, email: "", password: "", profileImage: image ?? UIImage(), joinedDate: joinedDate, coins: coins, activeChallenges: challenges)
}
else {
print("Document does not exist")
}
}
catch {
fatalError()
}
}
}
This is what the user model looks like:
class Account {
var id: String?
var firstName: String?
var secondName: String?
var email: String?
var password: String?
var profileImage: UIImage?
var coins: Int?
var joinedDate: String?
var activeChallenges: [Challenge]?
init(id: String, firstName: String,secondName: String, email: String, password: String, profileImage: UIImage, joinedDate: String, coins: Int, activeChallenges: [Challenge]) {
self.id = id
self.firstName = firstName
self.secondName = secondName
self.email = email
self.password = password
self.profileImage = profileImage
self.joinedDate = joinedDate
self.coins = coins
self.activeChallenges = activeChallenges
}
init() {
}
}
The problem is I don't understand how to map the activeChallenges from firestore to the array of the model. When I try : let challenges = document.get("activeChallenges") as? [Challenge] ?? []
The print contains an empty array, but when i do: let arrayWithNoOptionals = document.get("activeChallenges").flatMap { $0 } print("array without opt", arrayWithNoOptionals)
This is the output of the flatmap:
it returns an optional array
System can not know that activeChallenges is array of Challenge object. So, you need to cast it to key-value type (Dictionary) first, then map it to Challenge object
let challengesDict = document.get("activeChallenges") as? [Dictionary<String: Any>] ?? [[:]]
let challenges = challengesDict.map { challengeDict in
let challenge = Challenge()
challenge.challengeId = challengeDict["challengeId"] as? String
...
return challenge
}
This is the same way that you cast snapshot(document) to Account object

Problem fetching data from firebase by using struct file

struct UserClass {
var babyName: String!
var babyHeight: String!
var babyWeight: String!
var babyURL: String!
var uid: String!
var reference:DatabaseReference!
var key: String!
init?(snapshot: DataSnapshot?) {
guard let value = snapshot?.value as? [String:AnyObject],
let uid = value["uid"] as? String,
let babyName = value["BabyName"] as? String,
let babyURL = value["BabyURL"] as? String,
let babyHeight = value["BabyHeight"] as? String,
let babyWeight = value["BabyWeight"] as? String else {
return nil
}
self.key = snapshot?.key
self.reference = snapshot?.ref
self.uid = uid
self.babyURL = babyURL
self.babyName = babyName
self.babyHeight = babyHeight
self.babyWeight = babyWeight
}
func getuserData() -> String {
return ("BabyName = \(babyName)")
}
}
func fetchCurrentUserInfo() {
var currentUserRef = Database.database().reference().child("Users").child("\(userID)")
handler = currentUserRef.queryOrderedByKey().observe(DataEventType.value, with: { (snapshot) in
print("User data = \(snapshot.value)")
let user = UserClass(snapshot: snapshot)
print(user?.babyName)
self.babyName.text = user?.babyName
})
}
I am getting user data but not user.babyName. How can I fix this?
May be this will help you, as the db structure is not mentioned in question. but you have to iterate children one by one and then use for loop to fetch the exact data from firebase.
reference = FIRDatabase.database().reference()
reference.child("Users").queryOrderedByKey().observe(DataEventType.value, with: { (snapshot) in
if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] {
for snap in snapshots
{
let userId = child.childSnapshot(forPath: "userID").value! as! String
print(userId)
}
}
})

How to connect to new viewController with data saved in struct model of other viewController

How can I get the data that in Struct model in new viewController
I got a viewController when i print the var in Struct model it appeare just fine.
I created New viewController trying to get the same data in otherview of that struct model but when i print it it give me nil
I tryied to make the model equal to the new model in the new viewController
MessageController View
var messages = [Message]()
var users = [Contact]()
var messagesDicionary = [String: Message]()
var testMSG : Message?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let message = self.messages[indexPath.row]
let chatPartnerId = message.chatPartnerId()
let ref = Database.database().reference().child("users").child(chatPartnerId)
ref.observe(.value) { (snap) in
if let dictinoary = snap.value as? [String: AnyObject] {
guard let email = dictinoary["email"] ,let profileimage = dictinoary["profileimage"], let userid = dictinoary["userid"], let username = dictinoary["username"] else {
return
}
var user = Contact()
user.userid = chatPartnerId
user.userid = chatPartnerId
let userValue = Contact.init(email: email as? String, username: username as? String, profileimage: profileimage as? String, userid: userid as? String)
self.users.append(userValue)
self.showChatControllerToUser(user: userValue)
print(message.receivername)
}
}
}
result of Print Optional("Omar")
ChatMessagesController View
var user :Contact?
var users = [Contact]()
var message: Message?
var messagesArray = [Message]()
func observeChatMessages() {
guard let uid = Auth.auth().currentUser?.uid else {
return
}
let userMessagesRef = Database.database().reference().child("usersmesssages").child(uid)
userMessagesRef.observe(.childAdded) { (snap) in
let messageId = snap.key
let messageRef = Database.database().reference().child("messages").child(messageId)
messageRef.observeSingleEvent(of: .value, with: { (snapshot) in
guard let dictionary = snapshot.value as? [String:AnyObject] else {
return
}
let text = dictionary["text"] as? String
let receiverid = dictionary["receiverid"] as? String
let senderid = dictionary["senderid"] as? String
let time = dictionary["timestamp"] as? TimeInterval
let senderName = dictionary["sendername"] as? String
let receiverName = dictionary["receivername"] as? String
self.messagesArray.append(MessageValue)
self.chatTableView.reloadData()
print(self.message?.receivername)
})
}
}
result of print NIL
Message Model
struct Message {
var text: String?
var receiverid: String?
var senderid: String?
var timestamp: TimeInterval?
var sendername: String?
var receivername: String?
func chatPartnerId() -> String {
return (senderid == Auth.auth().currentUser?.uid ? receiverid : senderid)!
}
}
I tried to make in MessagesController
let chatMessage = ChatMessageController()
chatMessage.message = self.testMSG

Posts Being Uploaded Randomly in Collection View - Swift & Firebase

I have been refactoring my code and now I'm having trouble with the posts.
Whenever I add a new post to the collection view, it is being added in a random cell and out of order, instead of in the first post.
I know the reason is the fetchuser function and from what I'm being told due to the asynchronous loading, but don't know what to do in order to correct this.
Could someone help me figure out what to do so that my posts are added in the first cell?
#objc func observePostsAdoption() {
let postsRef = Database.database().reference().child("posts")
postsRef.queryOrdered(byChild: "postType").queryEqual(toValue: "adopt").observe(.value) { (snapshot) in
var tempPost = [Posts]()
for child in snapshot.children {
if let childSnapshot = child as? DataSnapshot {
let dict = childSnapshot.value as? [String: Any]
let newAdoptiondPost = Posts.transformPost(dict: dict!)
//This will look up all users at once
self.fetchUser(userid: newAdoptiondPost.userid!, completed: {
tempPost.insert(newAdoptiondPost, at: 0)
DispatchQueue.main.async {
self.postsadoption = tempPost
self.adoptionCollectionView.reloadData()
self.refresherAdoption.endRefreshing()
}
})
}
}
}
}
func fetchUser(userid: String, completed: #escaping ()-> Void ) {
Database.database().reference().child("users").child(userid).observeSingleEvent(of: .value) { (snapshot) in
if let dict = snapshot.value as? [String: Any] {
let user = UserProfile.transformUser(dict: dict)
self.users.insert(user, at: 0)
completed()
}
}
}
Here's my Post Struct
class Posts {
//UserView
var uid: String?
var author: UserProfile?
var timestamp: Date?
var userid: String?
func getDateFormattedString() -> String {
let formatter = DateFormatter()
formatter.dateFormat = "MMM d, HH:mm"
return formatter.string(from: self.timestamp!)
}
//Image
var photoUrl: URL?
//PostInformation View
var city: String?
var municipality: String?
var name: String?
var breed : String?
var phone : String?
var address : String?
var petType: String?
var genderType: String?
var comments: String?
}
extension Posts {
static func transformPost(dict: [String: Any]) -> Posts {
let post = Posts()
//Post Picture
let photoUrl = dict["photoUrl"] as? String
post.photoUrl = URL(string: photoUrl!)
//INFO POSTS
post.userid = dict["userid"] as? String
post.city = dict["city"] as? String
post.municipality = dict["municipality"] as? String
post.name = dict["name"] as? String
post.breed = dict["breed"] as? String
post.phone = dict["phone"] as? String
post.address = dict["address"] as? String
post.comments = dict["comments"] as? String
post.petType = dict["petType"] as? String
post.genderType = dict["gender"] as? String
let timestamp = dict["timestamp"] as? Double
post.timestamp = Date(timeIntervalSince1970: timestamp!/1000)
return post
}
}
If you already have the posts ordered by post type you can just do sorting depending on the timestamp. For example
#objc func observePostsAdoption() {
let postsRef = Database.database().reference().child("posts")
postsRef.queryOrdered(byChild: "postType").queryEqual(toValue: "adopt").observe(.value) { (snapshot) in
var tempPost = [Posts]()
for child in snapshot.children {
if let childSnapshot = child as? DataSnapshot {
let dict = childSnapshot.value as? [String: Any]
let newAdoptiondPost = Posts.transformPost(dict: dict!)
//This will look up all users at once
self.fetchUser(userid: newAdoptiondPost.userid!, completed: {
tempPost.insert(newAdoptiondPost, at: 0)
DispatchQueue.main.async {
self.postsadoption = tempPost
self.postsadoption.sort { (p1, p2) -> Bool in
return p1.timeStamp?.compare(p2.timeStamp!) == .orderdDescending
}
self.adoptionCollectionView.reloadData()
self.refresherAdoption.endRefreshing()
}
})
}
}
}
}
With that the posts adoption array will be sorted depending on the timestamp that you have.