react-native Realm的使用

本文详细介绍如何在React Native项目中安装并使用Realm数据库,包括数据模型定义、数据操作、迁移及通知机制等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 对象当

  • 修改Personname属性
  • 你增加或者移除 DogPersondogs属性
  • 通过修改属于Person Dogage 属性。

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的实践。

githubDemo地址

Realm 的官方文档链接:

Realm官方地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值