Інтеграція Firebase Realtime Database в мобільний додаток
Firebase Realtime Database (RTDB) — JSON-дерево з WebSocket-синхронізацією. Це не реляційна БД і не документна БД у класичному сенсі. Ключова фіча — офлайн-персистентність і real-time синхронізація з коробки. Але неправильна структура даних у RTDB перетворює ці переваги на проблему: підписка на вузол з глибоким вкладенням затягне все піддерево в пам'ять пристрою. Ми стикалися з проєктами, де через плоску структуру додаток вивантажував 50 МБ даних при кожному оновленні. Для real-time чатів RTDB у 2-3 рази швидше Firestore за затримкою доставки повідомлень. Як цього уникнути — розберемо нижче.
Чому неправильна структура даних вбиває продуктивність?
RTDB не підтримує JOIN і не вміє вибирати підмножину вузла. Якщо вкласти пости в профіль користувача, то при читанні users/$uid ви отримаєте всі пости цілком. При офлайн-персистентності вони кешуються, займаючи місце. Рішення — денормалізація та зворотні індекси. Приклад коректної структури:
{ "users": { "uid123": { "name": "Іван", "email": "ivan@..." } }, "posts": { "postId1": { "userId": "uid123", "text": "...", "createdAt": 1700000000 } }, "userPosts": { "uid123": { "postId1": true, "postId2": true } } } userPosts — зворотний індекс для отримання постів конкретного користувача без сканування всього вузла posts. Це стандартний патерн для RTDB. Ми гарантуємо, що структура буде спроєктована з урахуванням патернів Firebase — понад 10 проєктів інтеграції.
Як ми інтегруємо Firebase RTDB?
Процес роботи включає етапи, кожен з яких супроводжується Code Review і тестуванням на реальних пристроях. Досвід нашої команди — понад 20 проєктів з Firebase.
| Етап | Опис | Орієнтовний термін |
|---|---|---|
| Аналіз сценаріїв | Визначаємо, які дані потребують real-time | від 2 днів |
| Проектування структури | Денормалізація, зворотні індекси, шардування | від 3 днів |
| Налаштування правил безпеки | Валідація, аутентифікація, обмеження доступу | від 1 дня |
| Реалізація підписок | Офлайн-персистентність, вибір on('value') vs on('child_added') |
від 4 днів |
| Оптимізація кешу | keepSynced, розмір кешу |
від 1 дня |
| Навантажувальне тестування | Перевірка до 10k concurrent users | від 2 днів |
| Документація та передача | Архітектурна схема, опис правил, деплой | від 1 дня |
Вартість розраховується індивідуально після аналізу вашого проєкту. Зв'яжіться з нами для консультації.
Детальніше про транзакції
Лайки, лічильники, баланс — будь-який конкурентний інкремент потребує транзакцій:
const likeRef = database().ref(`/posts/${postId}/likes`); await likeRef.transaction(currentLikes => (currentLikes ?? 0) + 1); transaction() атомарно читає та записує. Якщо між read і write інший клієнт змінив значення — транзакція повторюється автоматично (до 25 разів). Для лайків це єдино правильний підхід — set(currentLikes + 1) дасть race condition при одночасних натисканнях.
Як уникнути витоків пам'яті при підписках?
import database from '@react-native-firebase/database'; useEffect(() => { const ref = database().ref(`/userPosts/${userId}`); const onValue = ref.on('value', snapshot => { const postIds = Object.keys(snapshot.val() ?? {}); setPostIds(postIds); }); const onChildAdded = ref.on('child_added', snapshot => { setPostIds(prev => [...prev, snapshot.key!]); }); return () => { ref.off('value', onValue); ref.off('child_added', onChildAdded); }; }, [userId]); Критично: завжди викликайте ref.off() при демонтуванні. on() без off() — memory leak: слухач живе вічно, перерендерює компонент, який уже видалено. У продакшні це крэш з Can't perform a React state update on an unmounted component. Альтернативно — абстрагуйте слухачі в користувацький хук з автоматичним знищенням.
Офлайн-персистентність
import database from '@react-native-firebase/database'; database().setPersistenceEnabled(true); database().setPersistenceCacheSizeBytes(10 * 1024 * 1024); // 10 MB setPersistenceEnabled(true) вмикає SQLite-кеш на пристрої. При офлайні додаток читає з кешу. При відновленні мережі — синхронізує зміни. Викликати лише один раз при ініціалізації, до першого підключення до БД.
keepSynced(true) на конкретному вузлі — попередньо завантажує дані та тримає в кеші, навіть якщо немає активних слухачів. Обережно: не застосовуйте до великих вузлів — RTDB скачає все дерево.
Налаштування правил безпеки
Згідно з Firebase Realtime Database Security Rules Guide, дефолтні правила RTDB — або всім читати/писати, або нікому. Обов'язково налаштовуємо перед продакшном:
{ "rules": { "users": { "$uid": { ".read": "$uid === auth.uid", ".write": "$uid === auth.uid" } }, "posts": { "$postId": { ".read": "auth != null", ".write": "auth != null && newData.child('userId').val() === auth.uid", ".validate": "newData.hasChildren(['userId', 'text', 'createdAt'])" } } } } .validate — перевіряє структуру даних перед записом. Без валідації клієнт може записати довільний JSON.
Вибір між RTDB та Firestore
| Критерій | RTDB | Firestore |
|---|---|---|
| Тип даних | Ієрархічні (JSON) | Документно-орієнтовані |
| Запити | Тільки за ключами та фільтрація | Складні запити, складені індекси |
| Масштабування | До 1M concurrent | Вище, автомасштабування |
| Real-time | Низька затримка (WebSocket) | Висока затримка, але ширший функціонал |
| Офлайн | Персистентність включена завжди | Опціонально |
| Ціна | $5/ГБ сховища + $1/ГБ трафіку | $0.06/100K операцій |
Висновок: RTDB — для чатів, присутності, ігор. Firestore — для складних запитів і великої кількості користувачів. Наша команда допомагає вибрати оптимальний варіант.
Що входить в роботу по інтеграції Firebase RTDB
- Архітектурна схема даних: денормалізація, зворотні індекси, шардування.
- Реалізація підписок з офлайн-персистентністю: код для React Native / Flutter / iOS / Android.
- Налаштування правил безпеки: валідація, аутентифікація, оптимізація.
- Навантажувальне тестування: перевірка до 10k concurrent users.
- Документація: опис API, правил, інструкція по деплою.
- Підтримка після запуску: гарантія 3 місяці.
Оцінимо ваш проєкт безкоштовно. Замовте інтеграцію Firebase RTDB вже сьогодні.







