- Published on
Firestore: massivlar (arrays) va map obyektlari bilan ishlash
- Authors
- Name
- ShoxruxC
- @iOSdasturchi
1. Array (Massiv) bilan ishlashdagi eng katta xato!
Tasavvur qiling, biz foydalanuvchining yoqtirgan narsalarini (masalan, kino, sport, kitob) bazada preferences: ["Sports", "Movies"] ko'rinishidagi Array sifatida saqlamoqchimiz.
Yangi o'rganayotgan ko'pchilik dasturchilar yangi element qo'shishda quyidagi mantiqni ishlatishadi:
- Bazadan foydalanuvchini (hujjatni) yuklab olamiz.
- Swift'dagi
preferences.append("Books")orqali mahalliy o'zgaruvchiga qo'shamiz. - Yangilangan massivni qaytadan bazaga
updateDataqilib jo'natamiz.
Nega bu usul juda xavfli? Tasavvur qiling, foydalanuvchi bir vaqtning o'zida ham telefonida, ham iPad'ida ilovaga kirgan. Telefonida "Sport" ni qo'shdi, ayni shu millisekundda iPad'ida "Kino" ni qo'shdi. Ikkala qurilma ham bazadan eski holatni o'qiydi va o'zining qo'shgan narsasini bazaga qayta yozadi. Natijada bittasining ma'lumoti o'chib ketadi (Data overwrite).
To'g'ri usul: FieldValue.arrayUnion va arrayRemove
Bunday muammolarni oldini olish uchun Firebase maxsus server-side komandalarni taqdim etgan. Bunda siz bazadan ma'lumotni yuklab olishingiz shart emas. Shunchaki Firebase'ga "Mana shu qiymatni borib o'sha massivning oxiriga qo'shib qo'y" deysiz.
Massivga ma'lumot qo'shish (Append)
Biz FieldValue.arrayUnion dan foydalanamiz:
func addUserPreference(userId: String, preference: String) async throws {
let data: [String: Any] = [
"preferences": FieldValue.arrayUnion([preference])
]
try await userCollection.document(userId).updateData(data)
}
Massivdan ma'lumot o'chirish (Remove)
Buning uchun FieldValue.arrayRemove ishlatiladi:
func removeUserPreference(userId: String, preference: String) async throws {
let data: [String: Any] = [
"preferences": FieldValue.arrayRemove([preference])
]
try await userCollection.document(userId).updateData(data)
}
Bu buyruqlar to'g'ridan-to'g'ri serverda bajariladi, shuning uchun ham bir vaqtda 10 ta joydan o'zgartirilsa ham ma'lumotlar yo'qolmaydi (Concurrency-safe).
2. Map (Murakkab obyektlar) bilan ishlash
Deylik, foydalanuvchining qaysidir bitta sevimli kinosi bor. Bu shunchaki matn (String) emas, u o'zining nomi, reytingi, va yiliga ega bo'lgan alohida model:
struct Movie: Codable {
let id: String
let title: String
let isPopular: Bool
}
Biz ushbu Movie modelini to'g'ridan-to'g'ri asosiy DBUser ichiga bitta "property" sifatida qo'shib yuborishimiz mumkin:
struct DBUser: Codable {
let userId: String
// ... boshqa maydonlar ...
var favoriteMovie: Movie? // Custom obyekt (Bazada bu Map deyiladi)
}
Buni bazadan o'qib olish (Decode) juda oson, oldingi darsdagi Codable buni avtomatik tarzda tushunadi (chunki Movie ham Codable qilingan).
Map obyektni bazaga yozishdagi muammo
Agar siz ushbu oynadagi o'zgarishni yangilamoqchi bo'lsangiz:
let myMovie = Movie(id: "1", title: "Avatar 2", isPopular: true)
// BU XATO! Firebase bunday maxsus Struct'ni updateData ichida to'g'ridan to'g'ri tushunmaydi
let data: [String: Any] = ["favorite_movie": myMovie]
Bunday yozish ilovaning "Crash" bo'lishiga (qotib qolishiga) sabab bo'ladi. Sababi, updateData funksiyasi faqat sodda ma'lumot turlarini (Dictionary) qabul qiladi.
Yechim: Biz custom Swift obyektimizni Firebase Encoder yordamida majburiy ravishda [String: Any] (Dictionary) shakliga o'tkazib olishimiz kerak:
func addFavoriteMovie(userId: String, movie: Movie) async throws {
// 1. Movie obyektini Dictionary'ga aylantirish (Encode)
guard let movieData = try? Firestore.Encoder().encode(movie) else {
throw URLError(.badServerResponse)
}
// 2. Hosil bo'lgan Map'ni bazaga jo'natish
let data: [String: Any] = [
"favorite_movie": movieData
]
try await userCollection.document(userId).updateData(data)
}
Xulosa
Array va Map'lar Firestore'da ma'lumotlarni tartibli va jamlangan holatda saqlash uchun juda zo'r vositalar hisoblanadi.
- Array ro'yxatlari uchun har doim
FieldValue.arrayUnionvaFieldValue.arrayRemoveishlating. - Murakkab Struct modellarini bazaga (Faqat bitta maydonini update qilish orqali) yozyotganda, albatta uni
Firestore.Encoder().encode(...)orqali Dictionary'ga o'zgartirib oling.
Ushbu qoidalar ma'lumotlar xavfsizligini taminlaydi va kutilmagan dastur xatoliklarining (crash) oldini oladi. Keyingi darslarda biz yanada ko'proq foydalanuvchilar (kolleksiyalar) orasidan qidiruv va filtrlash qanday ishlashini ko'rib chiqamiz!