使用realm数据库倒转关系实现高效查询效果

这是一篇找猫的主人的游戏。

Realm是一种非常高效便捷的移动端数据库框架。本文主要结合搜索并快速展示结果的实现,彰显realm在处理关系型数据库时的便捷高效。对于Realm还不了解的看官,请移步官方文档。 以下均以ReactNative上用到的RealmJS为例。

在表中定义Inverse Relationships

Realm在定义关系数据时,并不能自动解释反向关系。比如定义了Lucky是你的猫,数据库并不能反向推论你是Lucky的主人。这时,就需要我们明确在猫的属性下加一项——主人,做到明确联系。例如下面这段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const PersonSchema = {
name: 'Person',
properties: {
name: 'string',
cats: 'Cat[]'
}
}

const CatSchema = {
name:'Cat',
properties: {
name: 'string'
// No shorthand syntax for linkingObjects properties
owners: {type: 'linkingObjects', objectType: 'Person', property: 'cats'}
}
}

将具体属性写入数据表

写入的时候和其他情况的写入是一致的,唯一不同的是, linkingObjects 类型的属性,并不需要给它写值。比如:

1
2
3
4
5
6
7
8
9
10
try {
realm.write(() => {
const person = { name: 'Judy' };
const judy = realm.create('Person', person, true);
const lucky = realm.create('Cat', { name: 'Lucky' }, true);
judy.cats.push(lucky);
});
} catch (e) {
console.warn('error: ', e);
}

因为Person表的cats属性定义好了是Cat类型,所以,上面的例子可以确定Lucky是Judy的cats之一,然后,因为Cat类型有owners属性指向里Person表,所以这个关联在你往Person表写入值的时候就已经形成了。而不需要单独给owners属性赋值。

将搜索结果直接对应到响应的对象

如果我们要搜索名字包含‘Lu’猫的主人,可以写一个下面的方法:

1
2
3
4
5
6
7
8
9
function contentQuery(key) {
const contents = realm.objects('Cat');
const resultContents = contents.filtered(`text CONTAINS "${key}"`);
const result = [];
resultContents.forEach((element) => {
result.push(element.linkingObjects('Person', 'cats')[0]); //1
});
return resultMessages;
}

此处要注意1处反转搜索出来的linkingObjects结果是数组。
上例就可以利用Inverse Relationships的特性直接获得Person对象,进行进一步的处理,而不是常规的获得对象的id再进行filter,在效率上有所损失。