简体   繁体   English

绕过Firebase IN: limit in Swift

[英]Bypassing Firebase IN: limit in Swift

I have a query that I am doing with Google's Firestore where I get a query of posts from a collection.我有一个查询,我正在使用 Google 的 Firestore 进行查询,在那里我从一个集合中查询帖子。 This is a central collection of all posts on the.network but I want to be able to filter what comes from the server so the processing/filtering doesn't happen on the client side.这是 .network 上所有帖子的中央集合,但我希望能够过滤来自服务器的内容,这样处理/过滤就不会在客户端发生。 Essentially, I want to get a feed of posts from only account the user follows.本质上,我只想从用户关注的帐户中获取帖子提要。

Creating that array is easy enough.创建该数组很容易。 When the user logins it downloads the array of UID the user follows.当用户登录时,它会下载用户遵循的 UID 数组。 This array, theoretically, could be long.从理论上讲,这个数组可能很长。 Firestore has this handy '.whereField' option that can filter look through a String Array using in: like this. Firestore 有这个方便的“.whereField”选项,可以像这样使用 in: 过滤字符串数组的外观。

.whereField("userUID", in: auth.userFollowedAccounts!) .whereField("userUID", in: auth.userFollowedAccounts!)

It works perfectly but according to the documentation Firestore only allowed 10 items in the array when using in:.它工作得很好,但根据文档,当使用 in: 时,Firestore 只允许数组中的 10 个项目。 This causes an issues because I want users to be able to follow more then 10 accounts.这会导致问题,因为我希望用户能够关注 10 个以上的帐户。 I saw some other solutions from some other languages to get around this issue by splicing the array or doing some clever looping to go though all the options.我看到了一些其他语言的其他解决方案,通过拼接数组或通过所有选项对 go 进行一些巧妙的循环来解决这个问题。 Unfortunately, I can't seem to find a solution for Swift. Would love someone to take a look and help me brainstorm some work arounds for this.不幸的是,我似乎找不到 Swift 的解决方案。希望有人能帮我集思广益解决这个问题。

// Full Code Block // 完整代码块

    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
    }
}

Let me know if you have any questions.如果您有任何问题,请告诉我。

Here's a simple example using Firestore async/await calls to shorten the code.下面是一个使用 Firestore async/await 调用来缩短代码的简单示例。

The Firebase structure was not included in the question (please include that in questions) so I will craft one which may be similar to what you're using问题中未包含 Firebase 结构(请在问题中包含该结构),因此我将制作一个可能与您使用的结构相似的结构

Starting with a users collection which uses the users uid as the documentId, keeps the users name and then the users who they are following as an array从使用用户 uid 作为 documentId 的用户集合开始,保留用户名,然后将他们关注的用户作为数组

users
   uid_0
      user_name: "Leroy"
      following
          0: uid_9
   uid_1
      user_name: "Biff"
      following
          0: uid_0
          1: uid_2

In this, uid_0 is following uid_9 and uid_1 is following uid_0 and uid_2在此,uid_0 跟随 uid_9,uid_1 跟随 uid_0 和 uid_2

Then a posts collection snippit然后是一个帖子集合片段

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"

The posts have a message and the uid of the user that posted it.这些帖子有一条消息和发布它的用户的 uid。

Then the code.然后是代码。

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")
        }
    }
}

If I am user uid_1, I am following uid_0 and uid_2.如果我是用户 uid_1,那么我关注的是 uid_0 和 uid_2。 When this code is run, it will first query for all of the users I am following (uid_0, uid_2) then iterate over that list, which can be any number of users, to query the posts from each of those users, and output those posts to console.运行此代码时,它将首先查询我关注的所有用户(uid_0、uid_2),然后遍历该列表(可以是任意数量的用户)以查询每个用户的帖子,以及 output 那些发布到控制台。

So, if uid_0 has 3 posts and uid_2 has 3 posts the final output would look like this因此,如果 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

In this case I output to console but in code, you'd likely have some class to store the uid, name and post and then populate an array which backs a tableView or collection with that data在这种情况下,我 output 进行控制台,但在代码中,您可能有一些 class 来存储 uid、名称和发布,然后填充一个数组,该数组支持 tableView 或使用该数据的集合

class UserPostClass {
   var uid = ""
   var postId = ""
   var userName = ""
   var postMsg = ""
}

var userPostArray = [UserPostClass]()

and then once the array was populated, reload your tableView, view etc.然后一旦数组被填充,重新加载你的 tableView,视图等。

The one gotcha here is ensuring the UI is responsive - with small datasets this will work as is, but if you're loading thousands of posts (don't do that) you'll likely want to paginate your data to break it into smaller chunks.这里的一个问题是确保 UI 是响应式的——对于小型数据集,这将按原样工作,但如果您要加载数千篇文章(不要那样做),您可能需要对数据进行分页以将其分成更小的块。

The other thing to note is there is no ordering, so you'll likely want to add an orderBy clause另一件需要注意的事情是没有排序,所以你可能想要添加一个 orderBy 子句

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM