Firestore Pagination получает следующую порцию данных - PullRequest
0 голосов
/ 26 апреля 2020

У меня есть эта функция, которая выбирает документы из коллекции. Я получил этот лог c из документации Firestore, но я не понимаю цели addSnapshotListener.

В реальном сценарии мне нужно:

Сначала выполнить первый запрос, получить последний документ и передать его следующему запросу и так далее, верно? Так что это означает, что после каждого запроса мне нужно вернуть также последний документ? Если это так, зачем мне addSnapshotListener? Я могу получить lastSnapshot также от .getDocuments()

class HomeViewModel: ObservableObject, LoadProtocol {
    var firestoreService: FirestoreService = FirestoreService()
    @Published var items: [Item] = []


    let first: Query = Firestore.firestore().collection("items").limit(to: 1)
    var next: Query = Firestore.firestore().collection("items").limit(to: 1)

    init() {
        self.first.addSnapshotListener { (snapshot, error) in

            guard let snapshot = snapshot else {
                print("Error retreving cities: \(error.debugDescription)")
                return
            }

            guard let lastSnapshot = snapshot.documents.last else {
                // The collection is empty.
                return
            }

            // Construct a new query starting after this document,
            // retrieving the next 25 cities.
            self.next = self.firestoreService.db.collection("items")
                .start(afterDocument: lastSnapshot)

            // Use the query for pagination.

        }
    }

    func refresh() {
        self.firestoreService.fetchCollection(query: self.next) { (result: Result<[Item], Error>) in
            switch result {
            case .success(let items):
                self.items += items
                self.addToCategories()
            case .failure(let error):
                print(error)
            }
        }
    }
}

1 Ответ

1 голос
/ 27 апреля 2020

Проблема заключается в том, что вы смешиваете Basi c Cursor Pagination с Query Cursor Pagination в вашей реализации.

Basi c Разбиение курсора Часть вашего кода (вплоть до first.addSnapshotListener) верна и будет выполнять каждый раз, возвращая все больше и больше данных на карту каждый раз, когда вы вызываете функцию и разрешаете ее, однако часть Query Cursor Pagination никогда не будет вызываться, поэтому вы можете полностью удалить эту часть из своей реализации.

Таким образом, ваш код должен выглядеть следующим образом:

func fetchCollection<Collection: CollectionProtocol>(lastSnapshot: DocumentSnapshot?, query: Query, completion: @escaping (Result<[Collection], Error>) -> Void) {
    var first = query.limit(to: 1)

    if let lastSnapshot = lastSnapshot {
        first = query.start(afterDocument: lastSnapshot)
    }

    first.getDocuments() { (querySnapshot, error) in
        if let snapshot = querySnapshot {
            // print(snapshot.metadata.isFromCache)
            completion(.success(snapshot.documents.map { document -> Collection in
                return Collection(document: document)
            }))
        } else if let error = error {
            completion(.failure(error))
        }
    }
}

NOTE : Вы также можете добавить .limit(to:1) к вашей проверке lastSnapshot, поскольку, как и сейчас, она будет извлекать все документы, конечно, если это ваш предполагаемый лог c, игнорируйте эту заметку.


РЕДАКТИРОВАТЬ:

Если вы хотите использовать разбиение на страницы курсора запроса, вы можете следовать этому примеру, где слушатель находится вне функции fetchCollection и выполняется каждый раз, когда getDocuments () запускается и монтирует должен быть выполнен новый запрос:

//initial state of your app
var results = "nil";

//initial query
var query = db.collection("foo").document("bar").limit(to: 1);

//everytime you need more data fetched and on database updates to your snapshot this will be triggered
query.addSnapshotListener { querySnapshot, error in
    guard let snapshot = querySnapshot else {
        print("Error fetching snapshots: \(error!)")
        return
    }
    snapshot.documentChanges.forEach { 
        // update data
    }
    let next = db.collection("foo").document("bar").start(afterDocument: result.last!).limit(to: 1);
    query = next;
};

//initial load of data
fetchCollection();

//simply executes the query
func fetchCollection() {
    query.getDocuments { (document, error) in
        if let document = document, document.exists {
            if(result == "nil"){
                result = document.data().map();
            }else{
                result.map({ document.data() })
            }
        } else {
            print("Document does not exist")
        }

    }
}

ПРИМЕЧАНИЕ : имейте в виду, что это непроверенный пример, но он может быть хорошим началом укажите, что вам нужно в вашем приложении. Кроме того, я использую эту документацию для обновлений в режиме реального времени на приемнике, вы можете найти дополнительную информацию по этой ссылке.

...