Налаштування Realm бази даних в мобільному додатку
Realm — не просто обгортка над SQLite. Це об'єктна база даних зі своїм рухом, який зберігає дані в бінарному форматі .realm та працює з об'єктами напрямку, без ORM-прошарку. На практиці це означає, що запит на читання 10 000 об'єктів через Results<T> — це O(1) по пам'яті, тому що результати lazy та не матеріалізуються до звернення.
Підключення та базова налаштування
Для iOS використовується RealmSwift (SPM або CocoaPods), для Android — io.realm.kotlin Kotlin SDK. Старий Java SDK (io.realm:realm-android) офіційно deprecated — у нових проектах його не використовуємо.
// Android: інніціалізація Realm Kotlin SDK
val config = RealmConfiguration.Builder(
schema = setOf(User::class, Order::class, Product::class)
)
.name("app.realm")
.schemaVersion(3)
.migration(AppMigration()) // якщо schemaVersion > 0
.build()
val realm = Realm.open(config)
// iOS: відкриття Realm з конфігурацією
let config = Realm.Configuration(
fileURL: Realm.Configuration.defaultConfiguration.fileURL!
.deletingLastPathComponent()
.appendingPathComponent("app.realm"),
schemaVersion: 3,
migrationBlock: { migration, oldVersion in
if oldVersion < 2 {
migration.enumerateObjects(ofType: User.className()) { old, new in
new?["fullName"] = "\(old?["firstName"] ?? "") \(old?["lastName"] ?? "")"
}
}
}
)
Файл .realm за замовчуванням створюється в Documents — на iOS це попадає під iCloud backup автоматично. Якщо база велика та не критична для відновлення, виключаємо через URLResourceValues.isExcludedFromBackupKey = true.
Головна точка болі — міграції схеми
Realm вимагає явного інкремента schemaVersion при будь-якій зміні моделі: додали поле, переіменували, змінили тип — версія повинна вирости. Якщо додаток уже у production та у користувача .realm файл версії 2, а ви шипуєте версію 3 без блоку міграції — крах при відкритті бази.
Типова помилка: забули поднути schemaVersion при додаванні nullable поля. Realm 10+ для Kotlin SDK дозволяє додавати nullable поля без міграції (вони автоматично отримують null), але переіменування, видалення та зміна типу — завжди вимагають явної міграції.
Ще проблема — rollback. Якщо ви выпустили версію схеми 5, а потім хочете откатити релиз до версії 4 — база не відкриється: Realm не вміє downgrade міграції. Єдиний вихід — deleteRealmIfMigrationNeeded у dev-builds, але ніколи у production.
Запис та транзакції
Все зміни у Realm через транзакції. Не можна просто поменяти поле об'єкта поза write-блоком.
// Kotlin: запис
realm.write {
val user = query<User>("id == $0", userId).first().find()
user?.lastSeen = Clock.System.now()
user?.isOnline = true
}
// Читання з live results та підпискою на зміни
val users = realm.query<User>("isActive == true")
.sort("createdAt", Sort.DESCENDING)
.asFlow()
.collect { changes ->
when (changes) {
is InitialResults -> updateUI(changes.list)
is UpdatedResults -> updateUI(changes.list)
}
}
asFlow() — це реактивна підписка. Як тільки дані в базі змінятся, Flow еміттує новий результат. Ніякого polling, ніякого LiveData-wrapper вручну. Для MVVM це ідеально ложиться у ViewModel.
Thread safety
Realm-об'єкти не thread-safe. Відкритий у main thread об'єкт неможливо передавати у background coroutine. Кожен потік повинен відкривати свій Realm.open(config) або використовувати frozen() для передачі снепшота.
На практиці: якщо робите важку запис у IO-диспетчері, відкривайте Realm всередину того ж корутина. Не переіспользуйте інстанс з UI-шару.
Atlas Device Sync
Realm інтегрується з MongoDB Atlas Device Sync — це автоматична двустороння синхронізація локальної бази з хмаром. Для додатків з оффлайн-режимом це потужний варіант: конфлікт-резолюція, real-time оновлення, partition-based або flexible sync.
Підключається через SyncConfiguration замість стандартного RealmConfiguration, вимагає MongoDB Atlas аккаунт. Варто оцінювати окремо — це повноцінна бекенд-залежність.
Налаштування Realm для однієї платформи без sync: 3–5 днів. З міграційною стратегією, реактивними запитами та двома платформами: 1–2 тижні. Вартість розраховується індивідуально.







