skip to Main Content

I am trying to implement pagination into my app (infinite scrolling) but I don’t seem to wrap my head around the logic. I’ve gone as far as reading the first 20 documents, then when I scroll the "Read more posts" method is called which reads The whole remaining documents (80 in this case) which is not what I want. I want to read 20 posts at a time. Here is my code please point out at what I am doing wrong:

import UIKit
import FirebaseAuth
import Firebase

class HomeViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{

var following = [String]()

var posts = [Post]()
var fetchingMore = false

override func viewDidLoad() {
    super.viewDidLoad()
    
// reads first 20 posts
    let db = Firestore.firestore()
   
    db.collection("Posts").addSnapshotListener {
        snapshot , error in

        snapshot!.documentChanges.forEach { diff in
            if (diff.type == .added) {
                self.readPosts()
            }
        }
    }
}

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let height = scrollView.frame.size.height
    let contentYoffset = scrollView.contentOffset.y
    let distanceFromBottom = scrollView.contentSize.height - contentYoffset
    if distanceFromBottom < height {
        if(!fetchingMore){
            print("aaah")
            beginBatchFetch()
            return
        }
    }
}

func beginBatchFetch(){
    fetchingMore = true
    readMorePosts()
    fetchingMore = false
}


public func readPosts(){
    getFollowingList { following in
        let db = Firestore.firestore()
        
        db.collection("Posts").whereField("userId", in: following).order(by: "timestamp").limit(toLast: 20).addSnapshotListener{
            posts , error in
            
            if (error != nil){
                print("253 (error!.localizedDescription)")
                return
            }
            else{
                var tempPosts = [Post]()
                for doc in posts!.documents{
                    let daate = doc.data()["timestamp"] as! Timestamp
                    let mydbl = daate.dateValue().timeIntervalSince1970 * 1000

                    let post = Post(id: doc.data()["postId"] as! String, username: "@(doc.data()["username"]!)", userId: doc.data()["userId"] as! String , text: doc.data()["text"] as! String, timestamp: mydbl , numLikes: 0, numReposts: 0)

                    let isDuplicate = tempPosts.contains(where: { $0.id == post.id })

                    if(!isDuplicate){
                        tempPosts.insert(post, at: 0)
                    }
                } // end for

                self.posts = tempPosts
                    self.tableView.reloadData()
            }
        }
    }
}

func getFollowingList(_ completion: @escaping (_ followingList:[String]) -> Void){
    let db = Firestore.firestore()
    
    db.collection("Following").document(Auth.auth().currentUser!.uid).collection("Follows").addSnapshotListener {
        followingSnapshot , error in
        
        if(error != nil){
            print("243 (String(describing: error?.localizedDescription))")
            return
        }
        
        else{
            var tempFollowing = [String]()
            
            for following in followingSnapshot!.documents{
                tempFollowing.append(following.documentID)
            }
            return completion(tempFollowing)
        }
    }
}
}

func readMorePosts(){
    getFollowingList { following in
        let db = Firestore.firestore()
    
    let first = db.collection("Posts").whereField("userId", in: following).order(by: "timestamp", descending: true).limit(to: 20)

    first.addSnapshotListener { (snapshot, error) in
        guard let snapshot = snapshot else {
            print("134 (error?.localizedDescription)")
            return
        }
        
        guard let lastSnapshot = snapshot.documents.last else {
            return
        }
       
        // paginating ..
        let next = db.collection("Posts").whereField("userId", in: following)
            .order(by: "timestamp", descending: true)
            .start(afterDocument: lastSnapshot)
            .addSnapshotListener {
                docs , err in
                
                if err != nil{
                    print("152 (err!.localizedDescription)")
                    return
                }
                else{
                    for doc in docs!.documents{
                        let daate = doc.data()["timestamp"] as! Timestamp
                        let mydbl = daate.dateValue().timeIntervalSince1970 * 1000

                        let post = Post(id: doc.data()["postId"] as! String, username: "@(doc.data()["username"])" as! String, userId: doc.data()["userId"] as! String , text: doc.data()["text"] as! String, timestamp: mydbl , numLikes: 0, numReposts: 0)

                        let isDuplicate = self.posts.contains(where: { $0.id == post.id })

                        if(!isDuplicate){
                            self.posts.append(post)
                        }
                    } // end for
                        self.tableView.reloadData()
                }
            }
    }
}
}

2

Answers


  1. If you want to limit the number of results, you need to include a limit clause in your query:

    let next = db.collection("Posts").whereField("userId", in: following)
        .order(by: "timestamp", descending: true)
        .start(afterDocument: lastSnapshot)
        .limit(20)
        .addSnapshotListener {
    

    You’ll need to execute a query like this for every page, with an updated value for lastSnapshot each time.

    Login or Signup to reply.
  2. Here is my answer for FireStore pagination.

    I think it can solve your problem.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search