ITcoDe.Uz ← Maqolalar

Firebase

Firestore real vaqt sinxronizatsiyasi va men yo'l qo'ygan xato

Ma'lumot ikkita qurilma o'rtasida o'zi yangilanadi — bu sehrli tuyuladi. Toki bir kun mahalliy holat buluddagi to'g'ri ma'lumotni yozib yuborganini ko'rmaguningizcha.

Bakhrullo Nasrulloyev2026-08-14~7 daqiqa

Nima uchun Firestore

Yetkazib berish ilovasida buyurtma bir vaqtning o'zida uch joyda ko'rinishi kerak: mijoz telefonida, oshxona ekranida va admin panelida. Har biri holat o'zgarishini darhol bilishi shart.

Buni WebSocket bilan yozish mumkin, lekin unda server kerak, uni ushlab turish kerak, uzilishlarni qayta ulashni o'zingiz yozasiz. Firestore da esa onSnapshot bitta qatorda shu ishni bajaradi.

Asosiy naqsh

Tinglovchi o'rnatiladi va har o'zgarishda funksiya chaqiriladi:

import { collection, query, where, onSnapshot }
  from 'firebase/firestore';

const q = query(
  collection(db, 'orders'),
  where('status', 'in', ['new', 'cooking'])
);

const stop = onSnapshot(q, (snap) => {
  const orders = snap.docs.map(d => ({ id: d.id, ...d.data() }));
  renderKitchen(orders);
});

Yangi buyurtma qo'shilsa, holat o'zgarsa yoki hujjat o'chirilsa — funksiya o'zi chaqiriladi. Serverga so'rov yuborish, javob kutish, qayta so'rash kerak emas.

Muhim. onSnapshot obyekt qaytaradi — uni saqlang. Sahifa yopilganda yoki komponent olib tashlanganda tinglovchini to'xtatish kerak, aks holda ular to'planib boradi va o'qish limitini yeb qo'yadi.

Mening xatom

Unutilmas Ta'm da savat mahalliy holatda saqlanardi va bir vaqtning o'zida Firestore ga ham yozilardi. Mantiq shunday edi:

// ❌ noto'g'ri
onSnapshot(cartRef, (doc) => {
  cart = doc.data();      // buluddan olamiz
  render();
});

function addItem(item) {
  cart.items.push(item);          // mahalliy o'zgartiramiz
  setDoc(cartRef, cart);          // butun obyektni yozamiz
}

Bir qarashda mantiqiy. Amalda esa foydalanuvchi ikkita qurilmadan kirganda mahsulotlar yo'qola boshladi.

Nima sodir bo'lgan

Foydalanuvchi telefonda mahsulot qo'shadi. Shu paytda planshetda hali eski savat turibdi. Planshetda ham biror narsa qo'shiladi — va u butun obyektni yozib yuboradi. Telefondagi qo'shilgan mahsulot yo'qoladi.

Bu klassik "last write wins" muammosi. setDoc hujjatni to'liq almashtiradi, oradagi o'zgarishlarni hisobga olmaydi.

Yechim

Ikki narsani o'zgartirdim.

1. Butun obyektni emas, aniq maydonni yangilash

import { updateDoc, arrayUnion } from 'firebase/firestore';

async function addItem(item) {
  await updateDoc(cartRef, {
    items: arrayUnion(item)   // faqat qo'shadi
  });
}

arrayUnion serverda bajariladi. U mavjud massivga element qo'shadi va boshqa hech narsaga tegmaydi. Ikki qurilma bir vaqtda qo'shsa ham, ikkalasi ham saqlanadi.

2. Miqdor uchun tranzaksiya

Mahsulot sonini o'zgartirish murakkabroq, chunki eski qiymatni o'qib, yangisini hisoblash kerak. Bu yerda tranzaksiya ishlatiladi:

import { runTransaction } from 'firebase/firestore';

await runTransaction(db, async (tx) => {
  const snap = await tx.get(cartRef);
  const items = snap.data().items;
  const i = items.findIndex(x => x.id === itemId);
  items[i].qty += delta;
  tx.update(cartRef, { items });
});

Agar tranzaksiya davomida ma'lumot o'zgarsa, Firestore uni avtomatik qayta bajaradi. Poyga holati yo'qoladi.

Oflayn rejim

Firestore ning kutilmagan foydali tomoni — u oflayn ishlaydi. Internet uzilganda yozuvlar mahalliy navbatda turadi va aloqa tiklanganda o'zi yuboriladi.

Lekin bu foydalanuvchiga ko'rinishi kerak. Aks holda u buyurtma berdim deb o'ylaydi, aslida u hali yuborilmagan:

onSnapshot(cartRef, { includeMetadataChanges: true }, (doc) => {
  const pending = doc.metadata.hasPendingWrites;
  showSyncBadge(pending ? 'yuborilmoqda' : 'saqlandi');
});

Xarajatni nazorat qilish

Firestore har o'qish uchun hisoblaydi. onSnapshot esa har o'zgarishda hujjatlarni qayta o'qiydi. Beparvo yozilgan kod hisobni tez o'stiradi.

Amalda foydali bo'lgan qoidalar:

Xavfsizlik qoidalari

Oxirgi va eng ko'p unutiladigan narsa. Sinov rejimida Firestore hammaga ochiq bo'ladi va ko'pchilik shu holda chiqaradi.

match /orders/{id} {
  allow read:   if request.auth != null
             && resource.data.uid == request.auth.uid;
  allow create: if request.auth != null;
  allow update: if request.auth.token.admin == true;
}

Qoidasiz baza — bu ochiq baza. Har kim ma'lumotni o'qishi va o'chirishi mumkin.

Xulosa

Firestore real vaqt sinxronizatsiyasini juda oson qiladi va aynan shu osonlik xavf tug'diradi: mahalliy holatni to'g'ridan-to'g'ri yozish odati bir necha qurilma paydo bo'lganda ma'lumot yo'qolishiga olib keladi.

Qoida: butun obyektni yozmang. Aniq maydonni yangilang, massivlar uchun arrayUnion, hisob-kitob uchun tranzaksiya ishlating.

FirebaseFirestoreRealtimePWABackend