[英]Bypassing Firebase IN: limit in Swift
我有一个查询,我正在使用 Google 的 Firestore 进行查询,在那里我从一个集合中查询帖子。 这是 .network 上所有帖子的中央集合,但我希望能够过滤来自服务器的内容,这样处理/过滤就不会在客户端发生。 本质上,我只想从用户关注的帐户中获取帖子提要。
创建该数组很容易。 当用户登录时,它会下载用户遵循的 UID 数组。 从理论上讲,这个数组可能很长。 Firestore 有这个方便的“.whereField”选项,可以像这样使用 in: 过滤字符串数组的外观。
.whereField("userUID", in: auth.userFollowedAccounts!)
它工作得很好,但根据文档,当使用 in: 时,Firestore 只允许数组中的 10 个项目。 这会导致问题,因为我希望用户能够关注 10 个以上的帐户。 我看到了一些其他语言的其他解决方案,通过拼接数组或通过所有选项对 go 进行一些巧妙的循环来解决这个问题。 不幸的是,我似乎找不到 Swift 的解决方案。希望有人能帮我集思广益解决这个问题。
// 完整代码块
func getData() {
let db = Firestore.firestore()
db.collection("posts")
.order(by: "dateCreated", descending: true)
.whereField("userUID", in: auth.userFollowedAccounts!)
.limit(to: 10)
.getDocuments { (snap, err) in
if err != nil {
print((err?.localizedDescription)!)
return
}
self.post.removeAll()
for i in snap!.documents {
let data = Post(id: i.documentID, username: i.get("username") as? String, fullName: i.get("fullName") as? String, profilePictureURL: i.get("profilePictureURL") as? String, link: i.get("link") as? String, location: i.get("location") as? String, postImage: i.get("postImage") as? String, isVerified: i.get("isVerified") as? Bool, caption: i.get("caption") as? String, likeCounter: i.get("likeCounter") as? Int, dateCreated: i.get("dateCreated") as? String, userUID: i.get("userUID") as? String, isAdmin: i.get("isAdmin") as? Bool, pronouns: i.get("pronouns") as? String)
self.post.append(data)
}
self.lastDoc = snap!.documents.last
}
}
如果您有任何问题,请告诉我。
下面是一个使用 Firestore async/await 调用来缩短代码的简单示例。
问题中未包含 Firebase 结构(请在问题中包含该结构),因此我将制作一个可能与您使用的结构相似的结构
从使用用户 uid 作为 documentId 的用户集合开始,保留用户名,然后将他们关注的用户作为数组
users
uid_0
user_name: "Leroy"
following
0: uid_9
uid_1
user_name: "Biff"
following
0: uid_0
1: uid_2
在此,uid_0 跟随 uid_9,uid_1 跟随 uid_0 和 uid_2
然后是一个帖子集合片段
posts
post_0
post_msg: "Post 0 from uid_0"
post_uid: "uid_0"
post_1
post_msg: "Post 0 from uid_1"
post_uid: "uid_1"
post_2
post_msg: "Post 1 from uid_0"
post_uid: "uid_0"
这些帖子有一条消息和发布它的用户的 uid。
然后是代码。
func getPostsOfUsersIFollow() {
let usersCollection = self.db.collection("users")
let postsCollection = self.db.collection("posts")
let thisUserDoc = usersCollection.document("uid_1") //me
Task {
do {
let userResult = try await thisUserDoc.getDocument()
let usersIFollow = userResult.get("following") as? [String] ?? []
print(usersIFollow) //outputs the list of users uid's I follow
for uid in usersIFollow {
let usersPosts = try await postsCollection.whereField("post_uid", isEqualTo: uid).getDocuments()
for postDoc in usersPosts.documents {
let postMsg = postDoc.get("post_msg") as? String ?? "no msg"
print("post_id: \(postDoc.documentID) uid: \(uid) posted msg: \(postMsg)")
}
}
} catch {
print("need to handle error")
}
}
}
如果我是用户 uid_1,那么我关注的是 uid_0 和 uid_2。 运行此代码时,它将首先查询我关注的所有用户(uid_0、uid_2),然后遍历该列表(可以是任意数量的用户)以查询每个用户的帖子,以及 output 那些发布到控制台。
因此,如果 uid_0 有 3 个帖子而 uid_2 有 3 个帖子,那么最终的 output 将如下所示
["uid_0", "uid_2"]
post_id: post_0 uid_0 posted msg: Post 0 from uid_0
post_id: post_4 uid_0 posted msg: Post 1 from uid_0
post_id: post_6 uid_0 posted msg: Post 2 from uid_0
post_id: post_2 uid_2 posted msg: Post 0 from uid_2
post_id: post_5 uid_2 posted msg: Post 1 from uid_2
post_id: post_9 uid_2 posted msg: Post 2 from uid_2
在这种情况下,我 output 进行控制台,但在代码中,您可能有一些 class 来存储 uid、名称和发布,然后填充一个数组,该数组支持 tableView 或使用该数据的集合
class UserPostClass {
var uid = ""
var postId = ""
var userName = ""
var postMsg = ""
}
var userPostArray = [UserPostClass]()
然后一旦数组被填充,重新加载你的 tableView,视图等。
这里的一个问题是确保 UI 是响应式的——对于小型数据集,这将按原样工作,但如果您要加载数千篇文章(不要那样做),您可能需要对数据进行分页以将其分成更小的块。
另一件需要注意的事情是没有排序,所以你可能想要添加一个 orderBy 子句
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.