问题
Hey I have been following tutorials online to try and make a social media app and it works fine where all the posts made by users populates in one scene but in another scene I would like for the users who are currently logged in to be able to see their posts only instead of having to find their posts from a bunch of posts made by other users, below are my code samples:
Posts Code:
import Foundation
import UIKit
import Firebase
class Posts{
var id: String
var author: UserProfile
var text: String
var timestamp:Double
var createdAt:Date
init(id:String, author:UserProfile,text:String,timestamp:Double) {
self.id = id
self.author = author
self.text = text
self.timestamp = timestamp
self.createdAt = Date(timeIntervalSince1970: timestamp / 1000)
}
static func parse(_ key:String, _ data:[String:Any]) -> Posts? {
if let author = data["author"] as? [String:Any],
let uid = author["uid"] as? String,
let name = author["name"] as? String,
let photoURL = author["photoURL"] as? String,
let url = URL(string:photoURL),
let text = data["text"] as? String,
let timestamp = data["timestamp"] as? Double {
let userProfile = UserProfile(uid: uid, name: name, photoURL: url)
return Posts(id: key, author: userProfile, text: text, timestamp:timestamp)
func performDeepQuery() {
guard let user = Auth.auth().currentUser else { return }
let uid = user.uid
let ref = Database.database().reference().child("posts")
let query = ref.queryOrdered(byChild: "author/uid").queryEqual(toValue: uid)
query.observeSingleEvent(of: .value, with: { snapshot in
let allPosts = snapshot.children.allObjects as! [DataSnapshot]
for postSnap in allPosts {
let text = postSnap.childSnapshot(forPath: "text").value as? String ?? "No Text"
print(text)
//same as above
}
})
}
}
return nil }
}
func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0:
return theposts.count
case 1:
return fetchingMore ? 1 : 0
default:
return 0
} }
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.section == 0 { let cell = HomeViewControllerScene.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! Posting_TableViewCell
cell.set(theposts: theposts[indexPath.row])
return cell}
else {
let cell = HomeViewControllerScene.dequeueReusableCell(withIdentifier: "loadingCell", for: indexPath) as! LoadingCell
cell.spinner.startAnimating()
return cell
}
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cellHeights[indexPath] = cell.frame.size.height
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return cellHeights[indexPath] ?? 72.0
}
Please someone help me out here I have been scratching my head for a while with this!!!
回答1:
I believe the question is how to get the posts for a certain user. The structure looks good but no need to have a child node 'author' in each post so instead of this:
posts
post_id_0
author
author data
text: "Hello, World"
uid: "uid_0"
do this
posts
post_id_0
text: "Hello, World"
uid: "uid_0"
name: "usmaan"
photoURL:"https://firebasestorage..."
So now just query for this users posts (this is for Firestore, scroll down fo the RTDB solution)...
func getThisUsersPosts() {
let uid = "uid_0" //this users uid
self.db.collection("posts]").whereField("uid", isEqualTo: uid).getDocuments { (snapshot, error) in
if let err = error {
print(err.localizedDescription)
return
}
if let doc = snapshot?.documents {
for d in doc {
let text = d.get("text") as? String ?? "No Post Text"
print(text)
}
} else {
print("no posts found")
}
}
}
self.db points to my Firestore.
EDIT:
OP is using the Real Time Database so here's the code for that
func getThisUsersPosts() {
let uid = "uid_0"
let ref = self.ref.child("posts") //self.ref points to MY firebase.
let query = ref.queryOrdered(byChild: "uid").queryEqual(toValue: uid)
query.observeSingleEvent(of: .value, with: { snapshot in
let allPosts = snapshot.children.allObjects as! [DataSnapshot]
for postSnap in allPosts {
let text = postSnap.childSnapshot(forPath: "text").value as? String ?? "No Text"
print(text)
}
})
}
EDIT 2:
OP wants to keep their same structure.
To query for data that's two levels deep we use what's called Deep Query and will look something like this:
func performDeepQuery() {
let uid = "uid_0"
let ref = self.ref.child("posts")
let query = ref.queryOrdered(byChild: "author/uid").queryEqual(toValue: uid)
query.observeSingleEvent(of: .value, with: { snapshot in
let allPosts = snapshot.children.allObjects as! [DataSnapshot]
for postSnap in allPosts {
//populate your tableView datasource here
let post = PostClass()
post.postId = postSnap.key
post.name = postStap.childSnapshot("name").value as? String ?? "No Post Name"
post.text = postStap.childSnapshot("text").value as? String ?? "No Post Text"
self.postArray.append(post)
}
self.myTableView.reloadData()
})
}
which will perform a deep query on this structure
posts
post_0
author
uid: "uid_0"
name: "post 0 name"
text: "post 0 text"
The PostClass could be this
class PostClass {
var postId = ""
var name = ""
var text = ""
}
More Info:
To get the current users uid (which is covered in the getting started guide as well) and assuming you are authenticated (otherwise it will be nil)
guard let user = Auth.auth().currentUser else { return }
let uid = user.uid
来源:https://stackoverflow.com/questions/62046489/showing-post-data-from-logged-in-user-only-swift-xcode-firebase