1.安装
//下载
yarn add realm --save
or
npm i realm --save
以上两者二选一
//进行链接库Library
react-native link realm
在ios使用中可能会产生一个错误

解决方法
是rnpm的问题
需要在packaje.json中加入
"rnpm": {
"ios": {
"project": "ios/<project-name>.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 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]);
以上示例解决了的问题是,用户安装了应用程序记录了多个数据库版本,在以后的程序中你都可以获取到以前数据库中的数据。
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 Notifications
realm.addListener('change', updateUI);
// ..later remove the listener
realm.removeListener('change', updateUI);
// ..or unregister all listeners
realm.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属性 - 通过修改属于
PersonDog的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 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();
3.实际运用
在实际项目开发中我们通常使用封装的思想来进行实际应用,接下来通过一个简单的案例来演示:
首先我们使用豆瓣的免费接口作为测试数据的接口
https://api.douban.com/v2/movie/in_theaters?start=0&count=20
大家可以自行通过各种方式获取请求数据,查看数据结构
1.创建数据模型对象
Schemeas.js
const 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.js
import {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 的官方文档链接: