Published on

Firestore: bir vaqtning o'zida ko'plab hujjatlarni (multiple documents) yuklab olish

Authors

Nega "getDocuments(as:)" o'rnatilmagan?

Oldingi darslarda biz bitta foydalanuvchi profilini topish uchun getDocument(as: DBUser.self) dan foydalangan edik. Ushbu funksiya hujjatni topib, to'g'ridan-to'g'ri Swift modeliga o'girib (decode) berar edi.

Ammo, tasavvur qiling, siz butun bir products (mahsulotlar) kolleksiyasini tortib olmoqchisiz. Firebase kutubxonasida negadir getDocuments(as: Product.self) (ko'plikda) degan qulay funksiya yo'q! Nega? Chunki Firebase sizni ogohlantirmoqchi: "Agar sizning kolleksiyangizda 1 millionta mahsulot bo'lsa, siz hammasini bir vaqtda tortib olish orqali juda katta xarajatga (pulga) va xotira to'lib qolishiga sababchi bo'lishingiz mumkin. Shuning uchun buni o'z qo'lingiz bilan bajaring!"

Lekin bizning holatimizda, masalan 30-50 ta mahsulotni bir vaqtda ekranga chiqarishimiz kerak. Buning uchun biz Firebase'ning ushbu xatosini (yoki ataylab qilinmagan funksiyasini) o'zimiz tuzatamiz!

1. Qiyin (Standart) usul

Agar biz kutubxonani o'zgartirmasdan turib hamma mahsulotlarni tortib olmoqchi bo'lsak, kodimiz quyidagicha ko'rinish oladi:

func getAllProducts() async throws -> [Product] {
    // 1. Kolleksiyadagi barcha hujjatlarni "Snapshot" ko'rinishida olish
    let snapshot = try await productsCollection.getDocuments()

    var products: [Product] = []

    // 2. Har bir hujjatni bittalab aylanib chiqish (Loop)
    for document in snapshot.documents {
        // 3. Har birini alohida Decode qilish
        let product = try document.data(as: Product.self)
        products.append(product)
    }

    return products
}

Bu kod yaxshi ishlaydi. Lekin sizda nafaqat products, balki posts, comments, likes kabi kolleksiyalar ham bo'lsa, har biri uchun xuddi shu 15 qatorli kodni qayta-qayta yozaverasizmi? Yo'q, biz "Junior" emasmiz. Biz kodni "Generic" holatga o'tkazamiz!

2. Professional (Generic) usul

productsCollection obyekti turlari jihatidan Firebase'ning Query tipiga (klassiga) mansub. Shuning uchun, keling butun dasturimiz davomida barcha "Query" larga ishlaydigan bitta sehrli funksiya yaratamiz. Buning uchun Query ga Extension qo'shamiz:

import FirebaseFirestore
import FirebaseFirestoreSwift

extension Query {
    // T bu yerda har qanday Codable (Decodable) bo'la oladigan model bo'lishi mumkin (masalan: Product, DBUser, Comment)
    func getDocuments<T: Decodable>(as type: T.Type) async throws -> [T] {
        // 1. Snapshotni olish
        let snapshot = try await self.getDocuments()

        // 2. For loop o'rniga zamonaviy Map (High-order function) ishlatib bitta qatorda hal qilamiz
        return try snapshot.documents.map { document in
            try document.data(as: T.self)
        }
    }
}

TIP

Generics <T> siri: Ushbu T harfi qandaydir sirli narsa emas. U "Type" ya'ni "Istagan bitta Type" degan ma'noni bildiradi. Biz <T: Decodable> deyish orqali Swift'ga: "Bu funksiyaga faqat Decodable qilingan modellar kiritilishi mumkin" degan qoidani o'rnatdik.

Natija

Endi mahsulotlarni tortib olishdagi yuqoridagi 15 qatorli xunuk kodimiz o'rniga, har qanday kolleksiyada ishlaydigan, 1 qatorlik go'zal kodimiz bor:

func getAllProducts() async throws -> [Product] {
    return try await productsCollection.getDocuments(as: Product.self)
}

// Boshqa faylda foydalanuvchilarni olish kerak bo'lsa:
func getAllUsers() async throws -> [DBUser] {
    return try await usersCollection.getDocuments(as: DBUser.self)
}

Xulosa

Biz bitta Extension yozish orqali barcha Firebase kodlarimizni qanday masshtablash va takrorlanmas qilib (DRY qoidasi) yozishni o'rgandik. Lekin esingizda bo'lsin: getDocuments() bu xavfli buyruq! U kolleksiyadagi BARChA hujjatlarni yuklab oladi.

Agar kolleksiyangizda minglab hujjatlar bo'lsa, ularning orasidan o'zingizga kerakligini filtrlab, cheklov qo'yib (masalan 10 tasini) yuklab olishingiz shart. Buni Firebase'da Query (So'rovlar) deb ataymiz va bu aynan keyingi darsimizning bosh mavzusidir!

Buy mea coffee