在移動開發領域,realm是最熱門的跨平臺數據庫,沒有之一。而現在,realm已經把他的觸手伸到了服務端,在node.js服務器上也可以運行realm了(可以認爲是mongodb的競爭對手了)。但我們這裏所討論的realm仍然侷限於realm的本地數據庫,也就是它一開始被設計用來做的事:在ios上的競爭對手是fmdb/coredata, 安卓上的greendao等。
realm的js文檔非常完備和友好,推薦大家閱讀,我這裏會簡單介紹一下它主要的功能和使用。
https://realm.io/docs/javascript/latest/
1. schema. schema是realm的模型,也就是說它定義了model的格式;在rn上我們可以通過json和es 6的class兩種方式來對它進行定義; 這裏的name唯一代表了一個model的類型,如果需要升級之則需要給realmdb指定版本號:schemaVersion; 值得一提的是realm的模型升級機制非常完備,並且考慮了多版本升級的數據遷移問題,可謂是非常貼心了。model的所有字段都支持默認值設置,例:
miles: {type: 'int', default: 0}
2. realm支持的數據類型有:bool, string, date, int ,float, double ,data(數組); 作爲一個orm的數據庫,當然它也可以將realm的對象嵌套在model中存儲。此時我們在model裏面給字段指定類型的時候就要輸入嵌套對象的name。realm也支持將對象放在數組中作爲屬性,比如一個person可以擁有一個dogs的字段,這裏存放的是dog類型的對象數組。這是一種單向的鏈接關係(dog存放在dog表中,person則擁有他的dogs),我們還可以在dog裏面指定反向的鏈接關係,代碼示例如下:
const PersonSchema = {
name: 'Person',
properties: {
dogs: 'Dog[]'
}
}
const DogSchema = {
name:'Dog',
properties: {
// No shorthand syntax for linkingObjects properties
owners: {type: 'linkingObjects', objectType: 'Person', property: 'dogs'}
}
}
這裏的狗可能是屬於某個家庭,一個人也可能擁有多隻狗,所以這裏的狗和人存在正向和反向的鏈接關係。3. 字段可以設置爲索引值(付出的代價是插入變慢,收穫是查詢和搜索速度變快),且一個model可以設置一個主鍵值(類型可以是string或者int),可以通過主鍵直接訪問對象。
4. 關於操作:增刪改相關的操作一般來說需要放在write block中(transaction),代碼編寫起來也是比較方便的。realm支持對象的排序、過濾搜索等,還支持簡單的語句(類似於iOS中的NSPredicate)。值得一提的是realm的值都是lazy load的,所以對於大數據集的訪問可以直接獲取,而不用擔心內存溢出之類的問題,使用的時候先排序再通過slice獲取即可。 也是基於性能的考慮,realm獲取到的值的順序並不能保證和插入的順序一致,所以在開發時需要通過你自己的機制來保證順序(比如key或者基於值的排序等等)。
5. 同步訪問: realm db除了通過異步方式打開以外,也支持同步打開db進行操作(但不推薦,因爲同步方式會帶來可能的數據不一致等問題,還有可能有性能方面的問題),代碼如下:
const realm = new Realm({schema: [PersonSchema]});
// You can now access the realm instance.
realm.write(/* ... */);
6. 數據庫變更的通知通知機制讓我們可以以一種優雅的方式在多處操作數據庫並刷新UI。對於本地數據庫,realm提供了兩個維度的通知:
a. 數據庫變更通知
function updateUI() {
// ...
}
// Observe Realm Notifications
realm.addListener('change', updateUI);
這是一種很粗的listener,當write transaction發生時,就會觸發這個事件。所有的增、刪、改操作都應該在write transaction內部發生,也就是說會引發數據庫的變更。我們可以在這裏做一個簡單的reload.b. 數據集變更通知
該通知是綁定在realm對象/對象集合上的。回調的參數也有兩個:1.觀察的數據集本身 2.變更
示例代碼如下:
// Observe Collection Notifications
realm.objects('Dog').filtered('age < 2').addListener((puppies, changes) => {
// Update UI in response to inserted objects
changes.insertions.forEach((index) => {
let insertedDog = puppies[index];
...
});
// Update UI in response to modified objects
changes.modifications.forEach((index) => {
let modifiedDog = puppies[index];
...
});
// Update UI in response to deleted objects
changes.deletions.forEach((index) => {
// Deleted objects cannot be accessed directly
// Support for accessing deleted objects coming soon...
...
});
});
// Unregister all listeners
realm.removeAllListeners();
此外,realm也支持同時存在多個db以及配置不同的本地存儲路徑、支持64位的aes加密、支持inmemory模式等等,作爲一個移動db領域的巨頭玩家,我認爲realm可以作爲react native開發中本地數據庫的第一選擇。