Realm JavaScript
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公众号:山青咏芝(shanqingyongzhi)
➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/)
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:https://www.cnblogs.com/strengthen/p/11166081.html
➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。
➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
入门
安装
按照下面的安装说明通过npm安装Realm JavaScript ,或者在GitHub上查看源代码。
先决条件
- 确保您的环境已设置为运行React Native应用程序。按照React Native说明开始使用。
- 使用Realm的应用可以同时针对iOS和Android。
- 支持React Native 0.31.0及更高版本。
安装
-
创建一个新的React Native项目:
react-native init <project-name>
-
将目录更改为新项目(
cd <project-name>
)并添加realm
依赖项:npm install --save realm
-
接下来,将项目链接到本
realm
机模块。react-native link realm
Android警告:根据版本的不同,react-native link
可能会生成无效配置,正确更新Gradle(android/settings.gradle
和android/app/build.gradle
)但无法添加Realm模块。确认react-native link
已添加Realm模块; 如果没有,请使用以下步骤手动链接到库:
-
将以下行添加到
android/settings.gradle
:include ':realm' project(':realm').projectDir = new File(rootProject.projectDir, '../node_modules/realm/android')
-
将Realm添加到依赖项中
android/app/build.gradle
:// 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') }
-
添加导入并链接包
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>
);
}
}
然后,您可以在设备和模拟器中运行您的应用程序。
请注意,世博会不支持Realm,create-react-native-app
不起作用。
介绍
Realm JavaScript使您能够以安全,持久和快速的方式有效地编写应用程序的模型层。它旨在与React Native和Node.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。
三界
开放的领域
只需open
在Realm
类上调用静态方法即可打开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同步的RealminMemory
: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
和一组属性组成。每个属性具有名称和由或包含属性的类型的字符串,或与对象描述name
,type
,objectType
,optional
,default
,和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'
});
支持的类型
域支持下列基本类型:bool
,int
,float
,double
,string
,data
,和date
。
bool
属性映射到JavaScriptboolean
值int
,,float
和double
属性映射到JavaScriptnumber
值。内部'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',
}
}
可选属性
默认情况下,基本类型是非可选的,不支持存储null
或undefined
。通过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,因此它们只能在写入事务中进行修改。此外,List
s属于从中获取的基础对象 - 您只能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 的属性附加Dog
到Person
实例的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
向属性定义添加指示符以使该属性编入索引。这是支持的int
,string
,bool
,和date
物业类型:
var BookSchema = {
name: 'Book',
properties: {
name: { type: 'string', indexed: true },
price: 'float'
}
};
索引属性将极大地加速查询,其中以较慢的插入为代价比较属性的相等性。
主键
您可以primaryKey
在对象模型string
和int
属性中指定属性。声明主键可以有效地查找和更新对象,并为每个值强制实现唯一性。将具有主键的对象添加到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);
});
在上面的示例中,由于对象已经存在id
,1
并且我们已经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的启发。让我们简要总结一下支持的功能和语法:
- 比较操作数可以是属性名称或常量。至少有一个操作数必须是属性名称。特殊常量
false
,true
和null
。 - 时间戳可以以格式指定,
YYYY-MM-DD@HH:MM:SS:NANOSECONDS
并且YYYY-MM-DDTHH:MM:SS:NANOSECONDS
可以省略纳秒。 - 比较运算符
=
/==
,<=
,<
,>=
,>
,和!=
/<>
都支持int
,float
,double
,和Date
物业类型,例如age = 45
。 - boolean()属性支持比较运算符
=
/==
和!=
/ 。<>
bool
- 对于串和数据(
ArrayBuffer
)的属性,所述=
(和==
),!=
(和<>
), ,BEGINSWITH
,CONTAINS
和ENDSWITH
运营商都支持,例如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 >= 13
和cars.@avg.milage > 1000
。 - 关键路径也可以跟随链接对象(反向链接),例如
parents.age > 25
和parents.@count == 2
。 - 的
$
操作者可用于替代参数,例如child.age >= $0
(见下面的示例)。 - 排序和查找不同的值是可能的功能
SORT
和DISTINCT
如age > 20 SORT(name ASC, age DESC) DISTINCT(name)
。- 用于排序的排序可以是以下不区分大小写的文字中的一个:
ASC
,ASCENDING
,DESC
,DESCENDING
。 - 括号内的逗号分隔列表中可以显示任意数量的属性。
- 可以指示任意数量的排序/不同条件,它们将按指定的顺序应用。
- 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