首页 > 解决方案 > 使用 limit(toLast:) 查询时获取旧的分页快照

问题描述

我正在使用 Firestore 为我的应用程序构建聊天功能。我正在使用limit(toLast:),因为我是基于时间戳获取的,这种方法为我提供了保存在我的数据库中的最新消息。但是在尝试在加载旧消息之前获取快照/文档时给我带来了麻烦。这是我的代码:

fileprivate func paginateFetchMessages() {
    var query: Query!
    
    if let nextStartingSnap = self.lastDocumentSnapshot {
        query = DBCall.fireRef.collection("friendMessages")
        .document(currentUID)
        .collection(friendUID)
        .order(by: "timestamp").limit(toLast: 5).start(afterDocument: nextStartingSnap)
    } else {
        query = DBCall.fireRef.collection("friendMessages")
        .document(currentUID)
        .collection(friendUID)
        .order(by: "timestamp").limit(toLast: 5)
    }
    
    query.addSnapshotListener { querySnapshot, error in
        guard let snapshot = querySnapshot else {
            print("Error fetching snapshots: \(error!)")
            return
        }
        
        guard let lastSnap = snapshot.documents.last else {
            self.refreshControl.endRefreshing()
            return
        }
        
        print(snapshot.documents)
        
        self.lastDocumentSnapshot = lastSnap
        
        snapshot.documentChanges.forEach({ (change) in
            
            if change.type == .added {
               let data = change.document.data()
                let text = data["message"] as! String
                let fromID = data["fromID"] as! String
                let messageID = data["messageId"] as? String ?? ""
                let isRead = data["isRead"] as? Bool ?? false
                let timestamp = data["timestamp"] as! Timestamp
                
                let user = MessageKitUser(senderId: fromID, displayName: "")
                let message = MessageKitText(text: text, user: user, messageId: messageID, date: Date(), isRead: isRead, firDate: timestamp )
                
                self.insertMessage(message)
                self.refreshControl.endRefreshing()
            }
        })
    }
}

当我snapshot.documents.last什么都不用返回时,因为我最初是在获取“最后一个”文档。每次分页时,我都需要在最后一次之前获取 5 个快照。

如果这没有意义并且您有疑问,请告诉我。谢谢!!

标签: iosswiftfirebasegoogle-cloud-firestore

解决方案


假设您有 10 个文件:

[1,2,3,4,5,6,7,8,9,10]

limitToLast(5)将检索:

[6,7,8,9,10]

由于您使用的是start(afterDocument:,Firestore 在 document 之后启动6,这不是您想要的。相反,您想要end(beforeDocument:

query = DBCall.fireRef.collection("friendMessages")
.document(currentUID)
.collection(friendUID)
.order(by: "timestamp")
.end(beforeDocument: nextStartingSnap)
.limit(toLast: 5)

我也反转limit(toLast:and end(beforeDocument:。它对结果没有影响,但对我来说读起来稍微容易一些 - 因为这几乎是 Firestore 处理您的查询的方式:

  • 它将索引加载到timestamp.
  • 从此断绝了一切nextStartingSnap
  • 然后它返回结果中剩余的最后 5 个文档。

推荐阅读