How do I fetch posts of users that the current signed in user is following

好久不见. 提交于 2020-12-13 17:58:13

问题


I am using Cloud Firestore to store my data for my app. I am having a problem with fetching posts from users that the current signed in user follows. I have structured by database like this

Firestore-root
   |
   --- users (collection)
   |     |
   |     --- uid (documents)
   |          |
   |          --- name: "User Name"
   |          |
   |          --- email: "email@email.com"
   |
   --- following (collection)
   |      |
   |      --- uid (document)
   |           |
   |           --- userFollowing (collection)
   |                 |
   |                 --- uid (documents)
   |                 |
   |                 --- uid (documents)
   |
   --- posts (collection)
         |
         ------- postId (document)
                    |
                    |
                    --- uid: user
                    |
                    --- timestamp: 1570044062.261539
                    |
                    --- status: "status"

When I fetch the posts for the feed. I split the data returned by the query into batches and order the batch by the timestamp. Each batch has 10 posts however these batches do not contain posts from users that the current signed in user follows. It reads all the posts that are currently stored on the database regardless of who is following who

postsQuery = db.collection("posts").order(by: "timestamp", descending: true).limit(to: 10)

When the user signs in and loads their feed a request for the first 10 posts is sent by the fetchFirstBatch() function

private func fetchFirstBatch() {
        self.displaySpinner(onView: self.view)
        print("Fetching first batch")
        postsQuery.getDocuments { (snapshot, error) in
            guard let snapshot = snapshot else {
                print("Error retrieving batch: \(error.debugDescription)")
                return
            }

            guard let lastSnapshot = snapshot.documents.last else {
                return
            }

            for document in snapshot.documents {
                let data = document.data()
                let postType = data["post type"] as? String ?? ""

                if postType == PostType.Status.type {
                    let status = data["status"] as? String ?? ""
                    let timestamp = data["timestamp"] as? Double ?? 0
                    let uid = data["user id"] as? String ?? ""
                    let username = data["username"] as? String ?? ""

                    self.posts.append(Post(status: status, timestamp: timestamp, postType: PostType.Status, userId: uid, username: username))
                }
                self.tableView.insertRows(at: [IndexPath(row: self.posts.count - 1, section: 0)], with: .automatic)
            }

            self.lastSnapshot = lastSnapshot

            DispatchQueue.main.async {
                self.tableView.reloadData()
                self.removeSpinner()
            }
        }
    }

Once a user scrolls to the bottom of the table view that contains all the posts the next batch of posts are fetched by the fetchNextBatch() function

private func fetchNextBatch() {
        print("Fetching next batch")
        fetchingBatch = true

        postsQuery.start(afterDocument: lastSnapshot).getDocuments { (snapshot, error) in
            guard let snapshot = snapshot else {
                print("Error retrieving batch: \(error.debugDescription)")
                return
            }

            guard let lastSnapshot = snapshot.documents.last else {
                print("No more batches to fetch")
                self.fetchingBatch = false
                return
            }

            for document in snapshot.documents {
                let data = document.data()
                let postType = data["post type"] as? String ?? ""

                if postType == PostType.Status.type {
                    let status = data["status"] as? String ?? ""
                    let timestamp = data["timestamp"] as? Double ?? 0
                    let uid = data["user id"] as? String ?? ""
                    let username = data["username"] as? String ?? ""

                    self.posts.append(Post(status: status, timestamp: timestamp, postType: PostType.Status, userId: uid, username: username))
                }
                self.tableView.insertRows(at: [IndexPath(row: self.posts.count - 1, section: 0)], with: .automatic)
            }

            self.lastSnapshot = lastSnapshot

            DispatchQueue.main.async {
                self.tableView.reloadData()
            }

            self.fetchingBatch = false
        }
    }

How do I append all the posts of the users that the current signed in user is following whilst also paginating the data that is fetched each batch? The feed structure that I am trying to replicate is an Instagram feed.


回答1:


It is better to break your question down into smaller pieces, cause the question you've asked is a whole feature of your and its implementation.

I don't see why you separate the following collection from users' collection and put them in the top level of the data model, because basically in the there, you've created another layer to add a userFollowing sub-collection to the user document. You can relocate the userFollowing to the next level of user documents. Still, again, it depends on the fact that whether you want to store the whole data of the user (the people whom user follows) or fill their documents with the uid of their own.

But looking at the current state of your data model something similar to the code below can help you on this:

const arrayOfPeopleWhichUserFollows = await db.collection('following').doc(userId).collection('userFollowing').get()
      .then(querySnapshot => {
        return  querySnapshot.docs.map((doc) => {
          return doc.data().uid;
        });
      });


    // you have to measure the size of arrayOfPeopleWhichUserFollows to check whether it exceeds the limitation of 10
    // for using in the "where in" query from firestore
    // then breaks the array into a smaller piece, as small as 10 items per array and the repeat the below part for all the
    // fragmented arrays and append all the results into a single variable

    const firstPosts = await db.collection('posts')
      .where('uid', 'in', fragmentedArrayOfPeopleWhichUserFollows)
      .orderBy('timestamp', 'desc').limit(10);

    const posts = await firstPosts.get()
      .then(querySnapshot => {
        const lastVisible = querySnapshot.docs[querySnapshot.docs.length - 1];
        return querySnapshot.docs.map((post) => {
          return post.data();
        });
        const nextPosts = db.collection('posts')
          .where('uid', 'in', fragmentedArrayOfPeopleWhichUserFollows)
          .orderBy('timestamp', 'desc')
          .startAfter(lastVisible)
          .limit(10)
      });

consider reading these links:

how to write queries in firestore

how to paginate your data while querying from firebase

how to Manage indexes in Cloud Firestore



来源:https://stackoverflow.com/questions/59068295/how-do-i-fetch-posts-of-users-that-the-current-signed-in-user-is-following

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!