1.安装
//下载yarn add realm --save ornpm i realm --save以上两者二选一//进行链接库Libraryreact-native link realm复制代码
在ios使用中可能会产生一个错误
解决方法
是rnpm的问题需要在packaje.json中加入"rnpm": { "ios": { "project": "ios/.xcodeproj" }}复制代码
参考博客地址:
https://www.jianshu.com/p/a1846aa8d40a
https://stackoverflow.com/questions/44725619/fatal-attempting-to-release-access-but-the-mutator-does-not-have-access
2.使用
Realm supports the following basic types: bool, int, float, double, string, data, and date.
支持数据类型:
- bool
- int
- float
- double ‘int’ and ‘double’ are stored as 64 bits while float is stored with 32 bits.
- string
- data data properties map to ArrayBuffer,for example:[[object object],object object],object object]]
- date
定义一个数据模型
const CarSchema = { name: 'Car', properties: { // The following property types are equivalent make: { type: 'string'}, model: 'string', }}复制代码
可选属性
通常,基本数据类型是非可选(non-optional)并且不支持存储 null
undefined
类型。属性可以被指定为可选类型通过指定 optional
在属性定义时,或者通过简写语法(拼接?).
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 //可选属性可以设置为 null undefined charlie.birthday = undefined; charlie.displayName = 'Charles'; // Setting a non-optional property to null will throw `TypeError` // 非可选属性可以设置为 null // charlie.realName = null;});复制代码
增 和 改
增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);});复制代码
改const carSchemea = { name:'car', properties:{ miles:'int' }} let realm = new Realm.open({schema: [carSchemea})realm.write(() => { car.miles = 1100;});复制代码
删
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});复制代码
Migrations(迁移)
普通迁移
当你使用数据库时,你可以多次修改你的数据模型,例如支持以下的Person
模型:
const PersonSchema = { name: 'Person', properties: { firstName: 'string', lastName: 'string', age: 'int' }}复制代码
当我们更新我们的数据模型来新增一个 name
属性(property),如果我们简单的修改,如下:
const PersonSchema = { name: 'Person', properties: { name: 'string', age: 'int' }}复制代码
此时,如果我们保存所有数据用之前的模型版本,这里将会产生错误,当你想要打开一个新的版本你必须要进行迁移,简而言之,如果你新增或者删除一个属性(property),你只需要将schemaVersion增加,example如下:
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;});复制代码
通过上面的例子我们会发现,新增字段的值可以通过原有的值做相应的转换,如果你只是单纯的新增或者删除一个字段,你只需要改变schemaVersion的值即可(原则上采用增加的方式)。
Linear Migrations
这种迁移方式解决多个版本迁移问题。
如果用户跳过应用程序更新并且在跳过的版本中多次更改了属性,就可能发生这种情况。在这种情况下,您可能需要编辑旧的迁移代码,以便将数据从旧模式正确更新到最新模式。
可以通过按顺序运行多个迁移来避免此问题,确保将数据库升级到每个以前的版本,并且运行关联的迁移代码。遵循这种模式时,永远不必修改旧的迁移代码,尽管您将需要保留所有旧的模式和迁移块以供将来使用。下面举一个例子:
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 atlet nextSchemaIndex = Realm.schemaVersion(Realm.defaultPath);while (nextSchemaIndex < schemas.length) { const migratedRealm = new Realm(schemas[nextSchemaIndex++]); migratedRealm.close();}// open the Realm with the latest schemaRealm.open(schemas[schemas.length-1]);复制代码
以上示例解决了的问题是,用户安装了应用程序记录了多个数据库版本,在以后的程序中你都可以获取到以前数据库中的数据。
Notifications 机制
Realm
, Results
,List
这些objects提供了 addListener
方法来支持通知回调。当对象(object)更新的时候,通知回调就会被执行。
有两种通知机制的方法
-
Realm Notifications 适合简单的通知回调,当写(write transactions) 操作被提交(committed)。
-
Collection Notifications 适合更复杂的回调,当收到原数据插入(in sertions),删除(deletions)和更新(updates)
在某些情况下,写操作事物开始的时候监听者(listener)会被回调 - 数据库Realm更新到最新版本,Realm entities被观察到了修改(modified)或者删除(deleted)都会触发(triggers)通知。在这些情况中,监听者会运行在当前写事物(write transaction)的上下文环境中,一旦你想开启一个新的write transaction,将会抛出异常。你可以通过
Realm.isInTransaction
这个属性来判断你的code是否在执行写操作。
接下分别就两种通知机制举出example
1.Realm Notifications
Realm instances 会发出通知当写操作被提交
function updateUI() { // ...}// Observe Realm Notificationsrealm.addListener('change', updateUI);// ..later remove the listenerrealm.removeListener('change', updateUI);// ..or unregister all listenersrealm.removeAllListeners();复制代码
2.Collection Notifications
Collection notifications are delivered asynchronously(异步分发)
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'}, }};复制代码
假设你观察a list of dog owners 通过上面的模型,你将收到通知通过通过修改来匹配Person
对象当
- 修改
Person
的name
属性 - 你增加或者移除
Dog
给Person
的dogs
属性 - 通过修改属于
Person
Dog
的age
属性。
This makes it possible to discretely control the animations and visual updates made to the content inside your UI, instead of arbitrarily reloading everything each time a notification occurs.
原文更能表达这个含义所以不进行翻译。
// Observe Collection Notificationsrealm.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 listenersrealm.removeAllListeners();复制代码
3.实际运用
在实际项目开发中我们通常使用封装的思想来进行实际应用,接下来通过一个简单的案例来演示:
首先我们使用豆瓣的免费接口作为测试数据的接口
https://api.douban.com/v2/movie/in_theaters?start=0&count=20复制代码
大家可以自行通过各种方式获取请求数据,查看数据结构
1.创建数据模型对象
Schemeas.jsconst MoviesSchemea = { name:'Movies', properties:{ count:'int', start:'int', total:'int', title:'string', subjects: { type:'list',objectType:'Subject'}, }}const subjectSchemea = { name:'Subject', properties:{ alt:'string', id:'string', original_title:'string', title:'string', year:'string' }};export { MoviesSchemea, subjectSchemea}复制代码
2.设置数据迁移模型
Migrations.jsimport {MoviesSchemea,subjectSchemea} from 'Schemeas'export default[{ schema:[ MoviesSchemea, subjectSchemea, ], path:'movies.realm', schemaVersion:6, migration:(oldRealm,newRealm) => { }}]复制代码
默认输出的是一个数组
3.设置Realm管理类
RealmManager.js//引入对应模块import Realm from 'realm'import Migrations from 'Migrations'let realm = new Realm(Migrations[Migrations.length-1])//增 改const insertMovies = (movies) => { try { realm.write(()=>{ let oldMovies = realm.objects('Movies'); let count = oldMovies.length; if (oldMovies = null || count == 0){ realm.create('Movies',movies) }else { oldMovies[count - 1].count = movies.count; oldMovies[count - 1].start = movies.start; oldMovies[count - 1].total = movies.total; oldMovies[count - 1].title = movies.title; oldMovies[count - 1].subjects = movies.subjects; } }) } catch (error){ console.log(error) }}//查询const queryMovies = () =>{ return realm.objects('Movies')}//删除const deleteMovies = () =>{ try { realm.write(() => { realm.delete(realm.objects('Movies')); }) } catch (error){ console.log(error) }}export { insertMovies, queryMovies, deleteMovies}复制代码
这样我们一个数据库类就可以完美使用了,下面我们可以查看相应的demo来完成本次Realm的实践。
Realm 的官方文档链接: