Realm JavaScript

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公衆號:山青詠芝(shanqingyongzhi)
➤博客園地址:山青詠芝(https://www.cnblogs.com/strengthen/
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:http://www.javashuo.com/article/p-envwuhom-gc.html 
➤若是連接不是山青詠芝的博客園地址,則多是爬取做者的文章。
➤原文已修改更新!強烈建議點擊原文地址閱讀!支持做者!支持原創!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★javascript

入門

安裝

按照下面的安裝說明經過npm安裝Realm JavaScript ,或者在GitHub上查看源代碼html

先決條件java

  • 確保您的環境已設置爲運行React Native應用程序。按照React Native說明開始使用。
  • 使用Realm的應用能夠同時針對iOS和Android。
  • 支持React Native 0.31.0及更高版本。

安裝node

  • 建立一個新的React Native項目:react

    react-native init <project-name>
  • 將目錄更改成新項目(cd <project-name>)並添加realm依賴項:linux

    npm install --save realm
  • 接下來,將項目連接到本realm機模塊。android

    react-native link realm

Android警告:根據版本的不一樣,react-native link可能會生成無效配置,正確更新Gradle(android/settings.gradleandroid/app/build.gradle)但沒法添加Realm模塊。確認react-native link已添加Realm模塊; 若是沒有,請使用如下步驟手動連接到庫:ios

  1. 將如下行添加到android/settings.gradlegit

    include ':realm' project(':realm').projectDir = new File(rootProject.projectDir, '../node_modules/realm/android')
  2. 將Realm添加到依賴項中android/app/build.gradlegithub

    // When using Android Gradle plugin 3.0 or higher dependencies { implementation project(':realm') } // When using Android Gradle plugin lower than 3.0 dependencies { compile project(':realm') }
  3. 添加導入並連接包MainApplication.java

    import io.realm.react.RealmReactPackage; // add this import public class MainApplication extends Application implements ReactApplication { @Override protected List<ReactPackage> getPackages() { return Arrays.<ReactPackage>asList( new MainReactPackage(), new RealmReactPackage() // add this line ); } }

你如今準備好了。要查看Realm的運行狀況,請將class <project-name>如下內容替換爲如下內容App.js

const Realm = require('realm');

class <project-name> extends Component {
  constructor(props) {
    super(props);
    this.state = { realm: null };
  }

  componentWillMount() {
    Realm.open({
      schema: [{name: 'Dog', properties: {name: 'string'}}]
    }).then(realm => {
      realm.write(() => {
        realm.create('Dog', {name: 'Rex'});
      });
      this.setState({ realm });
    });
  }

  render() {
    const info = this.state.realm
      ? 'Number of dogs in this Realm: ' + this.state.realm.objects('Dog').length
      : 'Loading...';

    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          {info}
        </Text>
      </View>
    );
  }
}

而後,您能夠在設備和模擬器中運行您的應用程序。

請注意,世博會不支持Realmcreate-react-native-app不起做用。

介紹

Realm JavaScript使您可以以安全,持久和快速的方式有效地編寫應用程序的模型層。它旨在與React NativeNode.js一塊兒使用

這是一個簡單的例子:

const Realm = require('realm'); // Define your models and their properties const CarSchema = { name: 'Car', properties: { make: 'string', model: 'string', miles: {type: 'int', default: 0}, } }; const PersonSchema = { name: 'Person', properties: { name: 'string', birthday: 'date', cars: 'Car[]', picture: 'data?' // optional property } }; Realm.open({schema: [CarSchema, PersonSchema]}) .then(realm => { // Create Realm objects and write to local storage realm.write(() => { const myCar = realm.create('Car', { make: 'Honda', model: 'Civic', miles: 1000, }); myCar.miles += 20; // Update a property value }); // Query Realm for all cars with a high mileage const cars = realm.objects('Car').filtered('miles > 1000'); // Will return a Results object with our 1 car cars.length // => 1 // Add another car realm.write(() => { const myCar = realm.create('Car', { make: 'Ford', model: 'Focus', miles: 2000, }); }); // Query results are updated in realtime cars.length // => 2 }) .catch(error => { console.log(error); });

請注意,若是要將Realm用於服務器端/節點,則能夠在Realm Object Server文檔中找到其餘信息

Realm Studio

Realm Studio是咱們的首選開發人員工具,能夠輕鬆管理Realm數據庫和Realm平臺。使用Realm Studio,您能夠打開和編輯本地和同步的域,並管理任何Realm Object Server實例。它支持Mac,Windows和Linux。

Realm Studio

三界

開放的領域

只需openRealm調用靜態方法便可打開Realm 傳遞配置對象。咱們已經看到這已經在示例中使用了包含schema密鑰的配置對象

// Get the default Realm with support for our objects Realm.open({schema: [Car, Person]}) .then(realm => { // ...use the realm instance here }) .catch(error => { // Handle the error here if something went wrong });

有關配置對象的完整詳細信息,請參閱API參考以獲取配置除此以外schema該對象的一些更常見的鍵包括:

  • path:指定另外一個Realm的路徑
  • migration遷移功能
  • sync:一個同步對象,用於打開與Realm Object Server同步的Realm
  • inMemory:Realm將在內存中打開,而且對象不會被持久化; 一旦最後一個Realm實例關閉,全部對象都會消失
  • deleteRealmIfMigrationNeeded:若是須要遷移,刪除領域; 這在開發中頗有用,由於數據模型可能常常更改

默認領域

您可能已經注意到在前面的全部示例中都省略了path參數。在這種狀況下,使用默認的Realm路徑。您可使用Realm.defaultPath全局屬性訪問和更改默認的Realm路徑

打開同步領域

您是否但願使用Realm Mobile Platform同步全部Realm數據庫?全部與同步相關的文檔已移至咱們的平臺文檔中

其餘領域

在不一樣位置持有多個領域有時頗有用。例如,除了主Realm以外,您可能但願將一些數據與應用程序捆綁在Realm文件中。您能夠經過path在初始化領域時指定參數來完成此操做全部路徑都相對於應用程序的可寫文檔目錄:

// Open a realm at another path Realm.open({ path: 'anotherRealm.realm', schema: [CarSchema] }).then(/* ... */);

架構版本

打開Realm時可用的另外一個選項是schemaVersion屬性。省略時,schemaVersion屬性默認爲0您須要指定schemaVersion什麼時候使用包含與先前規範不一樣的對象的模式初始化現有Realm。若是架構已更新且架構未更新,schemaVersion則會引起異常。

const PersonSchema = { name: 'Person', properties: { name: 'string' } }; // schemaVersion defaults to 0 Realm.open({schema: [PersonSchema]});

若是你稍後再作這樣的事情:

const UpdatedPersonSchema = { // The schema name is the same, so previous `Person` object // in the Realm will be updated name: 'Person', properties: { name: 'string', dog: 'Dog' // new property } }; // this will throw because the schema has changed // and `schemaVersion` is not specified Realm.open({schema: [UpdatedPersonSchema]}); // this will succeed and update the Realm to the new schema Realm.open({schema: [UpdatedPersonSchema], schemaVersion: 1});

若是要檢索Realm的當前架構版本,可使用該Realm.schemaVersion方法執行此操做。

const currentVersion = Realm.schemaVersion(Realm.defaultPath);

同步開放的領域

您能夠經過簡單地調用構造函數並將配置對象傳遞給它來建立領域實例。一般不推薦這樣作,由於它會阻塞而且多是一個耗時的操做,特別是若是要運行遷移或者域同步而且您不但願在數據徹底下載以前冒險修改數據。

若是您仍想這樣作,模式很簡單:

const realm = new Realm({schema: [PersonSchema]}); // You can now access the realm instance. realm.write(/* ... */);

楷模

領域數據模型由初始化期間傳遞到Realm的架構信息定義。對象的模式由對象name和一組屬性組成。每一個屬性具備名稱和由或包含屬性的類型的字符串,或與對象描述nametypeobjectTypeoptionaldefault,和indexed字段。

const Realm = require('realm'); const CarSchema = { name: 'Car', properties: { make: 'string', model: 'string', miles: {type: 'int', default: 0}, } }; const PersonSchema = { name: 'Person', properties: { name: 'string', birthday: 'date', cars: 'Car[]' picture: 'data?', // optional property } }; // Initialize a Realm with Car and Person models Realm.open({schema: [CarSchema, PersonSchema]}) .then(realm => { // ... use the realm instance to read and modify data })

此時,經過類定義模型的支持是有限的。它在React Native中工做,但在Node中不工做。

若是要使用ES2015類(而且可能但願繼承現有功能),則只需在構造函數上定義模式:

class Person { get fullName() { return this.firstName + ' ' + this.lastName; } } Person.schema = { name: 'Person', properties: { firstName: 'string', lastName: 'string' } };

您如今能夠將類自己傳遞給schema打開配置屬性:

Realm.open({schema: [Person]}) .then( /* ... */ );

您能夠一直訪問屬性:

realm.write(() => { const john = realm.create('Person', { firstName: 'John', lastName: 'Smith' }); john.lastName = 'Peterson'; console.log(john.fullName); // -> 'John Peterson' });

支持的類型

域支持下列基本類型:boolintfloatdoublestringdata,和date

  • bool屬性映射到JavaScript boolean
  • int,, floatdouble屬性映射到JavaScript number值。內部'int'和'double'存儲爲64位,而float存儲爲32位。
  • string 屬性映射到 string
  • data 屬性映射到 ArrayBuffer
  • date 屬性映射到 Date

將基本屬性指定爲速記時,您能夠僅指定類型,而沒必要指定具備單個條目的字典:

const CarSchema = { name: 'Car', properties: { // The following property types are equivalent make: {type: 'string'}, model: 'string', } }

可選屬性

默認狀況下,基本類型是非可選的,不支持存儲nullundefined經過optional在屬性定義中指定指示符或使用簡寫語法,經過?在類型名稱後附加a 可使屬性成爲可選

const PersonSchema = { name: 'Person', properties: { realName: 'string', // required property displayName: 'string?', // optional property birthday: {type: 'date', optional: true}, // optional property } }; let realm = new Realm({schema: [PersonSchema, CarSchema]}); realm.write(() => { // optional properties can be set to null or undefined at creation let charlie = realm.create('Person', { realName: 'Charlie', displayName: null, // could also be omitted entirely birthday: new Date(1995, 11, 25), }); // optional properties can be set to `null`, `undefined`, // or to a new non-null value charlie.birthday = undefined; charlie.displayName = 'Charles'; // Setting a non-optional property to null will throw `TypeError` // charlie.realName = null; });

列表屬性

除了存儲單個值以外,還能夠將屬性聲明爲任何支持的基本類型的列表。這是經過附加[]類型名稱來完成的

const PersonSchema = { name: 'Person', properties: { name: 'string', testScores: 'double?[]' } }; let realm = new Realm({schema: [PersonSchema, CarSchema]}); realm.write(() => { let charlie = realm.create('Person', { name: 'Charlie', testScores: [100.0] }); // Charlie had an excused absense for the second test and was allowed to skip it charlie.testScores.push(null); // And then he didn't do so well on the third test charlie.testScores.push(70.0); });

訪問列表屬性時,將List返回一個對象。List具備與常規JavaScript數組很是類似的方法。最大的區別在於對a所作的任何更改都會List自動保存到底層Realm,所以它們只能在寫入事務中進行修改此外,Lists屬於從中獲取的基礎對象 - 您只能List經過從擁有對象訪問屬性來獲取實例,而且沒法手動建立它們。

雖然list屬性中的值能夠是可選的,但list屬性自己不能。optional使用longhand語法(values: {type: 'int[]', optional: true}指定list屬性將使列表中的值可選。

關係

一對一的關係

對於一對一關係,您能夠將name要引用的對象模式屬性指定爲屬性的類型:

const PersonSchema = { name: 'Person', properties: { // The following property definitions are equivalent car: {type: 'Car'}, van: 'Car', } };

使用對象屬性時,須要確保全部引用的類型都存在於用於打開Realm的模式中:

// CarSchema is needed since PersonSchema contains properties of type 'Car' Realm.open({schema: [CarSchema, PersonSchema]}) .then(/* ... */);

訪問對象屬性時,可使用常規屬性語法訪問嵌套屬性:

realm.write(() => { const nameString = person.car.name; person.car.miles = 1100; // create a new Car by setting the property to an object // with all of the required fields person.van = {make: 'Ford', model: 'Transit'}; // set both properties to the same car instance person.car = person.van; });

Realm中的對象屬性始終是可選的,沒必要明確指定,也不能使其成爲必需屬性

多對多關係

與基本屬性同樣,您也可使用對象列表來造成多對多關係。這能夠經過附加[]到目標對象模式的名稱,或者經過將屬性類型設置爲list並指定objectType

const PersonSchema = { name: 'Person', properties: { // The following property definitions are equivalent cars: {type: 'list', objectType: 'Car'}, vans: 'Car[]' } } let carList = person.cars; // Add new cars to the list realm.write(() => { carList.push({make: 'Honda', model: 'Accord', miles: 100}); carList.push({make: 'Toyota', model: 'Prius', miles: 200}); }); let secondCar = carList[1].model; // access using an array index

與其餘列表和一對一關係不一樣,多對多關係不能是可選的。

反向關係

連接是單向的。所以,若是to-many屬性Person.dogs連接到Dog實例而且Dog.owner連接到一個屬性Person,則這些連接彼此獨立。將a 屬性附加DogPerson實例的dogs屬性不會自動將dog的owner屬性設置爲this Person由於手動同步關係對是容易出錯,複雜和重複的信息,因此Realm提供連接對象屬性來表示這些反向關係。

經過連接對象屬性,您能夠從特定屬性獲取連接到給定對象的全部對象。例如,一個Dog對象能夠擁有一個名爲的屬性owners該屬性包含在其屬性Person中具備此確切Dog對象的全部對象dogs這是經過建立owners類型屬性linkingObjects而後指定它與Person對象的關係來完成的

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'} } }

linkingObjects屬性能夠指向到一個List屬性(一對多的關係)或Object屬性(對一的關係):

const ShipSchema = { name: 'Ship', properties: { captain: 'Captain' } } const CaptainSchema = { name: 'Captain', properties: { ships: {type: 'linkingObjects', objectType: 'Ship', property: 'captain'} } }

訪問linkingObjects屬性時,將Results返回一個對象,所以徹底支持進一步的查詢和排序linkingObject屬性屬於從中獲取的對象,沒法直接設置或操做。它們在提交事務時自動更新。

訪問linkingObjects沒有模式:若是你已經打開了一個域文件沒有指定一個模式,例如在一個領域的功能回調,你能夠獲得一個linkingObjects經過調用屬性linkingObjects(objectType, property)上的Object實例:

let captain = realm.objectForPrimaryKey('Captain', 1); let ships = captain.linkingObjects('Ship', 'captain');

連接對象屬性不能是可選的。

默認屬性值

能夠經過default在屬性定義中設置指示符來指定默認屬性值要使用默認值,請在對象建立期間保留未指定的屬性。

const CarSchema = { name: 'Car', properties: { make: {type: 'string'}, model: {type: 'string'}, drive: {type: 'string', default: 'fwd'}, miles: {type: 'int', default: 0} } }; realm.write(() => { // Since `miles` is left out it defaults to `0`, and since // `drive` is specified, it overrides the default value realm.create('Car', {make: 'Honda', model: 'Accord', drive: 'awd'}); });

索引屬性

您能夠indexed向屬性定義添加指示符以使該屬性編入索引。這是支持的intstringbool,和date物業類型:

var BookSchema = { name: 'Book', properties: { name: { type: 'string', indexed: true }, price: 'float' } };

索引屬性將極大地加速查詢,其中以較慢的插入爲代價比較屬性的相等性。

主鍵

您能夠primaryKey在對象模型stringint屬性中指定屬性。聲明主鍵能夠有效地查找和更新對象,併爲每一個值強制實現惟一性。將具備主鍵的對象添加到Realm後,沒法更改主鍵。

const BookSchema = { name: 'Book', primaryKey: 'id', properties: { id: 'int', // primary key title: 'string', price: 'float' } };

主鍵屬性會自動編入索引。

對領域中對象的更改 - 建立,更新和刪除 - 必須在write()事務塊中進行。請注意,寫入事務具備不可忽略的開銷; 您應該儘可能減小write代碼中

建立對象

使用如下create方法建立對象

try { realm.write(() => { realm.create('Car', {make: 'Honda', model: 'Accord', drive: 'awd'}); }); } catch (e) { console.log("Error on creation"); }

請注意,拋出的任何異常都write()將取消該事務。try/catch塊不會在全部示例中顯示,但這是一種很好的作法。

嵌套對象

若是對象具備對象屬性,則能夠經過爲每一個子屬性指定JSON值來遞歸地建立這些屬性的值:

realm.write(() => { realm.create('Person', { name: 'Joe', // nested objects are created recursively car: {make: 'Honda', model: 'Accord', drive: 'awd'}, }); });

更新對象

鍵入的更新

您能夠經過在寫入事務中設置其屬性來更新任何對象。

realm.write(() => { car.miles = 1100; });

使用主鍵建立和更新對象

若是模型類包含主鍵,則可讓Realm根據其主鍵值智能地更新或添加對象。這是經過將true第三個參數傳遞create方法來完成的

realm.write(() => { // Create a book object realm.create('Book', {id: 1, title: 'Recipes', price: 35}); // Update book with new price keyed off the id realm.create('Book', {id: 1, price: 55}, true); });

在上面的示例中,因爲對象已經存在id1而且咱們已經true爲第三個參數傳入值,所以更新price屬性而不是嘗試建立新對象。因爲title省略了屬性,所以該對象保留此屬性的原始值。請注意,在建立或更新具備主鍵屬性的對象時,必須指定主鍵。

刪除對象

能夠經過delete在寫入事務中調用方法來刪除對象

realm.write(() => { // Create a book object let book = realm.create('Book', {id: 1, title: 'Recipes', price: 35}); // Delete the book realm.delete(book); // Delete multiple books by passing in a `Results`, `List`, // or JavaScript `Array` let allBooks = realm.objects('Book'); realm.delete(allBooks); // Deletes all books });

查詢

查詢容許您從Realm獲取單個類型的對象,並可選擇過濾和排序這些結果。全部查詢(包括查詢和屬性訪問)在Realm中都是惰性的。只有在訪問對象和屬性時纔會讀取數據。這容許您以高效的方式表示大量數據。

執行查詢時,會返回一個Results對象。結果只是您的數據視圖,而且不可變。

從Realm中檢索對象的最基本方法是使用a上的objects方法Realm獲取給定類型的全部對象:

let dogs = realm.objects('Dog'); // retrieves all Dogs from the Realm

過濾

您能夠Results經過filtered在a List或a Results上使用查詢字符串調用方法來進行過濾

例如,如下內容將更改咱們以前的示例,以檢索全部顏色爲棕褐色且名稱以「B」開頭的狗:

let dogs = realm.objects('Dog'); let tanDogs = dogs.filtered('color = "tan" AND name BEGINSWITH "B"');

Realm支持的查詢語言受到Apple的NSPredicate的啓發讓咱們簡要總結一下支持的功能和語法:

  • 比較操做數能夠是屬性名稱或常量。至少有一個操做數必須是屬性名稱。特殊常量falsetruenull
  • 時間戳能夠以格式指定,YYYY-MM-DD@HH:MM:SS:NANOSECONDS而且YYYY-MM-DDTHH:MM:SS:NANOSECONDS能夠省略納秒。
  • 比較運算符===<=<>=>,和!=<>都支持intfloatdouble,和Date物業類型,例如age = 45
  • boolean()屬性支持比較運算符===!=<>bool
  • 對於串和數據(ArrayBuffer)的屬性,所述=(和==), !=<>), ,BEGINSWITHCONTAINSENDSWITH運營商都支持,例如name CONTAINS 'Ja'
  • 對於帶有LIKE運算符的字符串,能夠進行通配符比較,例如name LIKE '*an?'匹配「Jane」,「Dan」,「Shane」等。
  • 使用[c]例如字符串的字符串不區分大小寫的比較CONTAINS[c] 'Ja'請注意,只有字符「AZ」和「az」纔會被忽略。
  • Realm支持如下複合運算符:AND&&OR||NOT!,例如name BEGINSWITH 'J' AND age >= 32
  • 該集合表達式@count@size@min@max@sum而且@avg都支持列表屬性,如employees.@count > 5發現有更多的5個元素員工的清單。
  • 字符串和二進制屬性的聚合表達式@count@size,例如name.@size = 5,查找名稱爲5個字母的全部字符串
  • 關鍵路徑能夠遵循列表屬性關係,例如child.age >= 13cars.@avg.milage > 1000
  • 關鍵路徑也能夠跟隨連接對象(反向連接),例如parents.age > 25parents.@count == 2
  • $操做者可用於替代參數,例如child.age >= $0(見下面的示例)。
  • 排序和查找不一樣的值是可能的功能SORTDISTINCTage > 20 SORT(name ASC, age DESC) DISTINCT(name)
    • 用於排序的排序能夠是如下不區分大小寫的文字中的一個:ASCASCENDINGDESCDESCENDING
    • 括號內的逗號分隔列表中能夠顯示任意數量的屬性。
    • 能夠指示任意數量的排序/不一樣條件,它們將按指定的順序應用。
    • Sort或distinct不能獨立運行,這些條件必須附加到至少一個查詢過濾器。

關於如何查詢Realm的一個很是重要的例子是:

const Realm = require('realm'); const CarSchema = { name: 'Car', properties: { make: 'string', model: 'string', miles: {type: 'int', default: 0}, } }; const PersonSchema = { name: 'Person', properties: { name: 'string', cars: {type: 'list', objectType: 'Car'}, } }; // Initialize a Realm with Car and Person models Realm.open({schema: [CarSchema, PersonSchema]}) .then(realm => { // Add persons and their cars realm.write(() => { let john = realm.create('Person', {name: 'John', cars: []}); john.cars.push({make: 'Honda', model: 'Accord', miles: 1500}); john.cars.push({make: 'Toyota', model: 'Prius', miles: 2780}); let joan = realm.create('Person', {name: 'Joan', cars: []}); joan.cars.push({make: 'Skoda', model: 'Octavia', miles: 1120}); joan.cars.push({make: 'Ford', model: 'Fiesta', miles: 95}); joan.cars.push({make: 'VW', model: 'Golf', miles: 1270}); let jill = realm.create('Person', {name: 'Jill', cars: []}); let jack = realm.create('Person', {name: 'Jack', cars: []}); jack.cars.push({make: 'Porche', model: '911', miles: 965}); }); // Find car owners let carOwners = realm.objects('Person').filtered('cars.@size > 0'); console.log('Car owners') for (let p of carOwners) { console.log(` ${p.name}`); } // Find who has been driver longer than average let average = realm.objects('Car').avg('miles'); let longerThanAverage = realm.objects('Person').filtered('cars.@sum.miles > $0', average); console.log(`Longer than average (${average})`) for (let p of longerThanAverage) { console.log(` ${p.name}: ${p.cars.sum('miles')}`); } realm.close(); });

代碼段的輸出是:

Car owners
  John
  Joan
  Jack
Longer than average (1288.3333333333333)
  John: 4280
  Joan: 2485

排序

Results容許您根據單個或多個屬性指定排序條件和順序。例如,如下調用按上述數字按里程對上述示例中返回的汽車進行排序:

let hondas = realm.objects('Car').filtered('make = "Honda"'); // Sort Hondas by mileage let sortedHondas = hondas.sorted('miles'); // Sort in descending order instead sortedHondas = hondas.sorted('miles', true); // Sort by price in descending order and then miles in ascending sortedHondas = hondas.sorted([['price', true], ['miles', false]]);

Results 也能夠對您正在排序的對象連接的對象的值進行排序:

let people = realm.objects('Person'); // Sort people by the milage of their cars let sortedPeople = people.sorted('car.miles');

List基本類型的s能夠經過調用它們的值進行排序,sorted()而無需指定屬性:

let person = realm.objects('Person')[0]; let sortedTestScores = person.testScores.sorted();

請注意,Results僅在查詢排序時保證順序保持一致。出於性能緣由,不保證保留插入順序。

自動更新結果

Results實例是實時的,自動更新基礎數據的視圖,這意味着永遠沒必要從新獲取結果。修改影響查詢的對象將當即反映在結果中。對此的一個例外是當使用for...in或時for...of,它將始終迭代在迭代開始時與查詢匹配的對象,即便它們中的一些被刪除或修改以在迭代期間被過濾器排除。

let hondas = realm.objects('Car').filtered('make = "Honda"'); // hondas.length == 0 realm.write(() => { realm.create('Car', {make: 'Honda', model: 'RSX'}); }); // hondas.length == 1

這適用於全部Results狀況,包括那些被返回objectsfilteredsorted方法。

這種屬性Results不只使Realm快速高效,並且使您的代碼更簡單,更具反應性。例如,若是您的視圖依賴於查詢的結果,則能夠將其存儲Results在屬性中並對其進行訪問,而無需確保在每次訪問以前刷新其數據。

您能夠訂閱通知以瞭解Realm數據什麼時候更新,指示應該刷新應用程序的UI的時間,而無需從新獲取Results

限制結果

大多數其餘數據庫技術提供了從查詢中「分頁」結果的能力(例如SQLite中的'LIMIT'關鍵字)。這一般是爲了不從磁盤中讀取太多內容,或者一次將太多結果拉入內存中。

因爲Realm中的查詢是惰性的,所以根本不須要執行這種分頁行爲,由於Realm只會在顯式訪問後從查詢結果中加載對象。

若是出於UI相關或其餘實現緣由,您須要查詢中特定的對象子集,那麼就像獲取Results對象同樣簡單,只讀取您須要的對象。

let cars = realm.objects('Car'); // get first 5 Car objects let firstCars = cars.slice(0, 5);

遷移

使用數據庫時,您的數據模型極可能會隨時間而變化。例如,假設咱們有如下Person模型:

const PersonSchema = { name: 'Person', properties: { firstName: 'string', lastName: 'string', age: 'int' } }

咱們但願更新數據模型以要求name屬性,而不是分隔名和姓。爲此,咱們只需將架構更改成如下內容:

const PersonSchema = { name: 'Person', properties: { name: 'string', age: 'int' } }

此時,若是您使用之前的型號版本保存了任何數據,則新代碼與Realm存儲在磁盤上的舊數據之間將不匹配。發生這種狀況時,除非運行遷移,不然在嘗試使用新架構打開現有Realm時將引起異常。

執行遷移

您能夠經過更新schemaVersion並定義可選migration功能來定義遷移和關聯的模式版本您的遷移功能提供將數據模型從先前模式轉換爲新模式所需的任何邏輯。打開Realm時,Realm僅當須要遷移時,纔會應用遷移功能來更新給定的模式版本。

若是未提供遷移功能,則會自動添加任何新屬性,並在更新到新屬性時從數據庫中刪除舊屬性schemaVersion若是在升級版本時須要更新舊屬性或填充新屬性,能夠在遷移功能中執行此操做。例如,假設咱們想要遷移Person先前聲明模型。您能夠name使用舊的firstNamelastName屬性填充新架構的屬性:

Realm.open({ schema: [PersonSchema], schemaVersion: 1, migration: (oldRealm, newRealm) => { // only apply this change if upgrading to schemaVersion 1 if (oldRealm.schemaVersion < 1) { const oldObjects = oldRealm.objects('Person'); const newObjects = newRealm.objects('Person'); // loop through all objects and set the name property in the new schema for (let i = 0; i < oldObjects.length; i++) { newObjects[i].name = oldObjects[i].firstName + ' ' + oldObjects[i].lastName; } } } }).then(realm => { const fullName = realm.objects('Person')[0].name; });

成功完成遷移後,您的應用程序能夠像往常同樣訪問Realm及其全部對象。

線性遷移

使用上述遷移模式,遷移多個版本時可能會遇到問題。若是用戶跳過應用更新而且在跳過的版本中屢次更改屬性,則可能會發生這種狀況。在這種狀況下,您可能須要編輯舊的遷移代碼,以便將數據從舊架構正確更新到最新架構。

經過順序運行多個遷移能夠避免此問題,確保將數據庫升級到每一個先前版本並運行關聯的遷移代碼。遵循此模式時,永遠沒必要修改舊的遷移代碼,儘管您須要保留全部舊的模式和遷移塊以供未來使用。這看起來像一個例子:

const schemas = [ { schema: schema1, schemaVersion: 1, migration: migrationFunction1 }, { schema: schema2, schemaVersion: 2, migration: migrationFunction2 }, ... ] // the first schema to update to is the current schema version // since the first schema in our array is at let nextSchemaIndex = Realm.schemaVersion(Realm.defaultPath); while (nextSchemaIndex < schemas.length) { const migratedRealm = new Realm(schemas[nextSchemaIndex++]); migratedRealm.close(); } // open the Realm with the latest schema Realm.open(schemas[schemas.length-1]);

通知

RealmResultsList對象提供addListener了註冊通知回調的方法。每當更新對象時,都將調用更改通知回調。

有兩種通知,「領域通知」(提交寫入事務時通知的簡單回調)和「收集通知」(在插入,刪除和更新時接收更改元數據的更復雜的回調)。

在某些狀況下,能夠在事務開始時調用偵聽器- 若是Realm進入最新版本,或者以觸發通知的方式修改或刪除正在觀察的Realm實體。在這些狀況下,偵聽器在當前寫入事務的上下文中運行,所以嘗試在通知處理程序中開始新的寫入事務將引起異常。您可使用該Realm.isInTransaction屬性來肯定您的代碼是否在寫入事務中執行。

領域通知

每次提交寫入事務時,Realm實例都會向其餘實例發送通知。要註冊通知:

function updateUI() { // ... } // Observe Realm Notifications realm.addListener('change', updateUI); // ..later remove the listener realm.removeListener('change', updateUI); // ..or unregister all listeners realm.removeAllListeners();

收集通知

收集通知包含描述在細粒度級別上發生了哪些更改的信息。這包括自上次通知以來已插入,刪除或修改的對象的索引。集合通知是異步傳遞的:首先是初始結果,而後是在修改集合中任何對象的任何寫入事務以後,從集合中刪除對象,或者將新對象添加到集合中。

給出的通知回調函數addListener在發生這些更改時接收兩個參數。第一個是更改的集合,第二個是changes具備關於受刪除,插入和修改影響的集合索引的信息對象。

前兩個,刪除插入,只要對象開始和中止成爲集合的一部分,就會記錄索引。這會將對象添加到Realm或從Realm中刪除它們時考慮在內。爲此,Results當您篩選特定值並更改對象以使其如今與查詢匹配或再也不匹配時也適用。對於基於的集合List,這適用於在關係中添加或刪除對象時。

每當對象的屬性發生更改時,您的應用程序都會收到有關修改的通知,這些屬性之前是該集合的一部分,而且仍然是其中的一部分。當to-one和to-many關係發生變化時,也會發生這種狀況,但不會考慮反向關係的變化。

class Dog {} Dog.schema = { name: 'Dog', properties: { name: 'string', age: 'int', } }; class Person {} Person.schema = { name: 'Person', properties: { name: {type: 'string'}, dogs: {type: 'list', objectType: 'Dog'}, } };

咱們假設您正在觀察上面的模型代碼給出的狗主人名單。在下列狀況下,您將收到有關匹配Person對象的修改的通知

  • 你修改Personname屬性。
  • 您添加或刪除DogPersondogs財產。
  • 您修改屬於age屬性的屬性DogPerson

這使得能夠離散地控制對UI內容進行的動畫和視覺更新,而不是每次發生通知時任意從新加載全部內容。

collectionListenerRetainer = realm.objects('Dog').filtered('age < 2'); // Observe Collection Notifications function listener(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... ... }); }); collectionListenerRetainer.addListener(listener); // Unregister all listeners realm.removeAllListeners(); // OR Unregister this listener collectionListenerRetainer.removeListener(listener);

使用同步領域

您是否但願使用Realm Mobile Platform同步全部Realm數據庫?全部與同步相關的文檔已移至咱們的平臺文檔中

加密

請注意咱們許可證的出口合規部分,由於若是您位於有美國出口限制或禁運的國家/地區,它會對使用Realm進行限制。

Realm支持在建立Realm時經過提供64字節加密密鑰,使用AES-256 + SHA2加密磁盤上的數據庫文件。

var key = new Int8Array(64); // pupulate with a secure key Realm.open({schema: [CarObject], encryptionKey: key}) .then(realm => { // Use the Realm as normal var dogs = realm.objects('Car'); });

這使得存儲在磁盤上的全部數據均可以根據須要使用AES-256進行透明加密和解密,並使用SHA-2 HMAC進行驗證。每次得到Realm實例時都必須提供相同的加密密鑰。

使用加密領域時,性能受到很小影響(一般低於10%)。

例子

能夠在realm-js存儲庫中的GitHub上找到示例

請注意,在Android上,您須要安裝NDK而且必須設置ANDROID_NDK環境變量。

export ANDROID_NDK=/usr/local/Cellar/android-ndk/r10e

故障排除

缺乏領域構造函數

若是您的應用程序崩潰,告訴您未找到Realm構造函數,您能夠嘗試如下幾種方法:

首先,跑 react-native link realm

若是這沒有幫助,而且您的問題出在Android上,請嘗試:

在您的MainApplication.java文件中添加如下內容

import io.realm.react.RealmReactPackage;

並添加RealmReactPackage到包列表:

protected List getPackages() { return Arrays.asList( new MainReactPackage(), new RealmReactPackage() // add this line ); }

在如下兩行中添加settings.gradle

include ':realm'
project(':realm').projectDir = new File(settingsDir, '../node_modules/realm/android')

若是您的問題出如今iOS上,請嘗試:

  1. 關閉全部模擬器/設備構建
  2. 中止在終端中運行的包管理器(或者更好的是,只需從新啓動終端)
  3. 在Finder中打開app根目錄中的ios文件夾
  4. 進入build文件夾(注意:你不會在atom中看到這個build文件夾,因此只需右鍵單擊ios並在finder中單擊open)
  5. 刪除構建文件夾內的全部內容(只需移動到垃圾箱並保留垃圾,以防您擔憂)
  6. 運行react-native run-ios以重建整個事物

Chrome調試很慢

咱們意識到這一點。這樣作的緣由是,因爲Realm是用C ++編寫的而且運行本機代碼,所以它必須在設備/模擬器上運行。可是考慮到零複製體系結構,每次檢查存儲在Realm中的對象時,咱們都須要經過RPC線在realm對象中發送值。

咱們正在研究解決此問題的各類潛在解決方案。若是您想跟蹤它,能夠按照GitHub問題進行操做

沒法下載 realm-sync-cocoa

咱們已經看到一些報告,因爲下載問題,用戶沒法構建他們的應用程序。症狀是您看到相似的錯誤消息Error: unexpected end of file at Zlib.zlibOnError [as onerror] (zlib.js:142:17) errno: -5, code: 'Z_BUF_ERROR' }

能夠手動下載所需的文件,而後構建應用程序。步驟是:

  1. 找到您的項目目錄,而後找到node_modules/realm/vendor/realm-ios它會是空的。
  2. download-realm.lock使用如下命令建立文件echo SYNC_SERVER_FOLDER=sync SYNC_ARCHIVE=realm-sync-cocoa-3.7.0.tar.gz SYNC_ARCHIVE_ROOT=core > download-realm.lock版本號(此處爲3.7.0)必須與更改日誌中的Realm Sync版本匹配。
  3. 找到下載的文件,realm-sync-cocoa-3.7.0.tar.gz執行此命令tar -xzvf realm-sync-cocoa-3.7.0.tar.gz -C yourProjectDirectory/node_modules/realm/vendor/realm-ios
  4. 你會發現該目錄再也不是空的。複製目錄下的全部文件core並將其粘貼到目錄下yourProjectDirectory/node_modules/realm/vendor/realm-ios

崩潰報告

咱們鼓勵您在應用程序中使用崩潰報告器。許多Realm操做可能在運行時失敗(與任何其餘磁盤IO同樣),所以從應用程序收集崩潰報告將有助於肯定您(或咱們)能夠改進錯誤處理和修復崩潰錯誤的區域。

大多數商業崩潰記者均可以選擇收集日誌。咱們強烈建議您啓用此功能。在拋出異常和不可恢復的狀況時,Realm會記錄元數據信息(但沒有用戶數據),這些消息能夠在出現問題時幫助調試。

相關文章
相關標籤/搜索