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会记录元数据信息(但没有用户数据),这些消息能够在出现问题时帮助调试。

相关文章
相关标签/搜索