- Published on
Firestore pagination: limitlar, kursorlar va hujjatlarni sanash (count)
- Authors
- Name
- ShoxruxC
- @iOSdasturchi
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 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:
- Avvalgi qidiruvdan qaytgan eng oxirgi hujjatning o'zini (DocumentSnapshot) saqlab qo'yishimiz kerak.
- 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.