Published on

Firestore queries: ma'lumotlarni filtrlash, tartiblash va indekslash (indexes)

Authors

Nega ma'lumotlarni ilovada (lokal) filtrlamaymiz?

Deylik, bazamizda 1 millionta foydalanuvchi bor. Biz faqatgina "Toshkent"da yashaydiganlarini ekranga chiqarmoqchimiz. Boshlovchi dasturchilar nima qiladi? Avval 1 millionta ma'lumotning hammasini telefonga tortib olib (download), keyin Swift'dagi users.filter { $0.city == "Toshkent" } funksiyasini ishlatishadi. Oqibati:

  1. Internet trafiki tugaydi (millionlab ma'lumot o'qildi).
  2. Firebase'dan keladigan to'lov (bill) juda kattalashib ketadi (chunki siz har bitta o'qilgan hujjat uchun pul to'laysiz).
  3. Ilova qotib qoladi.

To'g'ri yechim: Qidiruvni (Query) to'g'ridan-to'g'ri Firebase serverida bajarib, faqat kerakli natijalarinigina telefonga tushirish kerak. Buni Server-side Filtering deymiz.

1. Tartiblash (Sorting)

Ma'lumotlarni biror bir mezon bo'yicha tartiblash uchun order(by:) dan foydalanamiz:

func getProductsSortedByPrice(descending: Bool) async throws -> [Product] {
    // order(by:) orqali narx bo'yicha tartiblash
    return try await productsCollection
        .order(by: "price", descending: descending) // true = Qimmatdan arzonga, false = Arzondan qimmatga
        .getDocuments(as: Product.self)
}

2. Filtrlash (Filtering)

Endi faqat ma'lum bir turdagi (masalan, telefonlar) mahsulotlarni ajratib olamiz. Buning uchun whereField ishlatiladi:

func getProductsByCategory(category: String) async throws -> [Product] {
    // whereField orqali faqat category'si kiritilgan so'zga teng bo'lganlarini olish
    return try await productsCollection
        .whereField("category", isEqualTo: category)
        .getDocuments(as: Product.self)
}

NOTE

isEqualTo dan tashqari boshqa ko'plab mantiqiy operatorlar mavjud:

  • isLessThan (<)
  • isGreaterThan (>)
  • arrayContains (Massiv ichidan izlash)
  • in (Bir nechta qiymatlardan biriga to'g'ri kelsin)

3. Murakkab so'rovlar (Compound Queries) va Indekslar

Eng qiziq joyi! Endi tasavvur qiling, biz ham filtrlashni, ham tartiblashni bir vaqtda qilmoqchimiz: "Faqat telefonlarni (Filter), qimmatidan arzonga qarab tartiblab ber (Sort)".

Buning uchun biz yuqoridagi ikkala komandani zanjir (chain) qilib ulaymiz:

func getProducts(category: String, descending: Bool) async throws -> [Product] {
    return try await productsCollection
        .whereField("category", isEqualTo: category) // 1. Filtrlash
        .order(by: "price", descending: descending)  // 2. Tartiblash
        .getDocuments(as: Product.self)
}

Kutilmagan xatolik (Crash)

Agar bu kodni birinchi marta ishga tushirsangiz, ilovangizda xatolik yuz beradi (Crash) va konsolda shunday yozuv paydo bo'ladi: The query requires an index. You can create it here: https://console.firebase.google.com/...

Nega bunday bo'ldi? Firebase o'zining tezligini yo'qotmasligi uchun birdaniga ikkita katta amaliyotni (ham filter, ham sort) oddiy holatda bajara olmaydi. Firebase'ga buning uchun Composite Index (Murakkab Indeks) deb nomlangan maxsus ko'rsatma kerak.

Muammoning yechimi

  1. Xatolik xabaridagi havola (link) ga bosing. U sizni to'g'ridan-to'g'ri Firebase Console sahifasiga olib o'tadi.
  2. Ekranda "Create Index" degan oyna chiqadi.
  3. Shunchaki tasdiqlash (Create) tugmasini bosing.
  4. Firebase ushbu indeksni yaratishi uchun 3-5 daqiqa vaqt ketadi (Status: Building...).
  5. Indeks yaratib bo'lingach (Status: Enabled), ilovangizni qayta ishga tushiring.

Ana endi, sizning so'rovingiz qanchalik murakkab bo'lmasin, Firebase uni yarim millisekund ichida hisoblab, to'g'ri natijani qaytaradi!

CAUTION

Siz har bir turdagi murakkab kombinatsiya uchun alohida indeks yaratishingiz kerak. Masalan:

  1. category (isEqualTo) + price (descending) = Bitta indeks
  2. category (isEqualTo) + price (ascending) = Yana bitta yangi indeks talab qilinadi. Firestore bazasida maksimal 200 ta Composite Index yaratish mumkin. Bu ko'rsatkich har qanday yirik loyiha uchun ham bemalol yetadi.
Buy mea coffee