Published on

Firestore pagination: limitlar, kursorlar va hujjatlarni sanash (count)

Authors

Limit qo'yish (Limiting Data)

Tasavvur qiling, siz Instagram yaratdingiz. Foydalanuvchi ilovaga kirganda barcha 1 millionta postni darhol yuklab olmaysiz-ku, to'g'rimi? Buning o'rniga faqat dastlabki 10 ta post yuklanadi. Buning uchun Firestore'da limit(to:) (boshidan boshlab) yoki limit(toLast:) (oxiridan boshlab) funksiyalari mavjud:

func getFirstTenProducts() async throws -> [Product] {
    // Faqat dastlabki 10 ta mahsulotni yuklab olish
    return try await productsCollection
        .limit(to: 10)
        .getDocuments(as: Product.self)
}

Pagination (Qismlab yuklash)

Keling, haqiqiy Pagination mantiqini tuzamiz. Dastlabki 10 ta mahsulot yuklandi. Foydalanuvchi ekranni pastga skroll qildi va ro'yxat oxiriga yetdi. Endi navbatdagi 10 tasini qanday yuklaymiz?

Noto'g'ri (yoki xavfli) yondashuv

Ba'zilar "Narxi 100danarzonbolganlarni"deyaqidiruvnidavomettiradistart(after:100).Ammonarxiaynan100 dan arzon bo'lganlarni" deya qidiruvni davom ettiradi `start(after: 100)`. Ammo narxi aynan 100 bo'lgan bir nechta mahsulotlar qolib ketishi (skip) mumkin.

Eng to'g'ri (Best Practice) yondashuv: Document Cursors

Biz start(afterDocument:) funksiyasidan foydalanamiz. Buning ishlashi uchun:

  1. Avvalgi qidiruvdan qaytgan eng oxirgi hujjatning o'zini (DocumentSnapshot) saqlab qo'yishimiz kerak.
  2. Yangi qidiruv jo'natayotganda Firebase'ga: "Mana shu hujjatdan keyingilaridan boshlab yana 10 ta ber" deb aytamiz.

Shuning uchun biz avvalgi darsdagi getDocuments funksiyamizni (hozircha faqat [Product] qaytarayotgan edi) endi ham Array, ham oxirgi hujjatni (Tuple ko'rinishida) qaytaradigan qilib o'zgartiramiz:

extension Query {
    // Endi funksiya Array va oxirgi hujjatni (DocumentSnapshot) qaytaradi
    func getDocumentsWithSnapshot<T: Decodable>(as type: T.Type) async throws -> ([T], DocumentSnapshot?) {
        let snapshot = try await self.getDocuments()

        // Barcha hujjatlarni modellar ro'yxatiga o'girish
        let products = try snapshot.documents.map { document in
            try document.data(as: T.self)
        }

        // Eng oxirgi hujjatni topish
        let lastDocument = snapshot.documents.last

        return (products, lastDocument)
    }
}

Endi u qanday ishlatiladi?

// Kelajakdagi so'rovlar uchun oxirgi hujjat xotirada saqlanadi
var lastDocumentSnapshot: DocumentSnapshot? = nil

func getNextBatchOfProducts() async throws -> [Product] {
    var query: Query = productsCollection.limit(to: 10)

    // Agar avvalgi yuklangan hujjat mavjud bo'lsa, qidiruv o'shandan keyin boshlanadi
    if let lastDoc = lastDocumentSnapshot {
        query = query.start(afterDocument: lastDoc)
    }

    // So'rovni yuboramiz va natijani qabul qilamiz
    let (newProducts, newLastDoc) = try await query.getDocumentsWithSnapshot(as: Product.self)

    // Keyingi qidiruv uchun yangi oxirgi hujjatni saqlab qo'yamiz
    self.lastDocumentSnapshot = newLastDoc

    return newProducts
}

Mana shunday usulda Instagram yoki TikTok kabi Cheksiz Skroll (Infinite Scroll) yaratsangiz bo'ladi!

Hujjatlarni sanash (Aggregation Count)

Sizning kolleksiyangizda qancha foydalanuvchi borligini bilmoqchisiz. Oldinlari buning yagona yo'li — barcha millionta hujjatni yuklab olib, ularning sonini sanash edi (bu millionta read degani, Firebase sizdan ko'p pul oladi).

Yaqinda Firebase Aggregation Queries xususiyatini qo'shdi. Endi Firebase barcha hujjatlarni yuklab olmasdan turib, shunchaki ularning sonini bitta Integer raqamda hisoblab, qaytara oladi! Bu o'ta tez va arzon (1000 ta hujjatni sanash = bor yo'g'i 1 marta o'qish (read) puliga teng).

func getProductsCount() async throws -> Int {
    // getAggregation orqali faqat raqamni qaytarib olish
    let snapshot = try await productsCollection.count.getAggregation(source: .server)
    return Int(truncating: snapshot.count)
}

Xulosa

Katta ma'lumotlar bilan ishlaganda har doim limit() dan foydalaning va Paginationni joriy qiling. Foydalanuvchilar soni (yoki layklar soni) kabi statistikani chiqarish uchun esa Count Aggregation komandalaridan foydalansangiz, ilovangiz juda yengil va tejamkor bo'ladi.

Buy mea coffee