Docs 菜单
Docs 主页
/ /
Atlas Device SDKs
/ /

定义 Realm 对象模型 - Node.js SDK

在此页面上

  • 定义 Realm 对象类型
  • 使用 JavaScript 类定义 Realm 对象类型
  • 支持的属性类型
  • 定义对象属性
  • 指定可选属性
  • 指定主键
  • 为属性创建索引
  • 设置全文搜索索引
  • 定义默认属性值
  • 将属性或类映射到其他名称
  • 定义关系属性
  • 定义对一关系属性
  • 定义对多关系属性
  • 定义反向关系属性
  • 定义嵌入式对象属性
  • 定义非对称对象
  • 定义非结构化数据

要定义Realm 对象类型,请创建一个指定该类型的nameproperties的模式对象。 在域中的对象类型中,类型名称必须是唯一的。 有关如何定义特定属性的详细信息,请参阅定义对象属性。

您可以使用 JavaScript 类定义模式(如同本页上的大多数示例),但也可以将它们定义为 JavaScript 对象。

const Car = {
name: "Car",
properties: {
_id: "objectId",
make: "string",
model: "string",
miles: "int?",
},
};

您可以使用 JavaScript 类定义 Realm 对象类型。要使用类作为对象类型,请在静态属性 schema 上定义对象模式。

class Car extends Realm.Object {
static schema = {
name: "Car",
properties: {
_id: { type: "objectId", default: () => new Realm.BSON.ObjectId() },
make: "string",
model: "string",
miles: "int?",
},
primaryKey: "_id",
};
}

注意

类名不得超过 57 个 UTF-8 字符。

打开域时,将类本身传递给 Realm.Configuration 对象的模式属性。然后,您就可以正常读写数据。

const realm = await Realm.open({
path: "myrealm",
schema: [Car],
});
let car1;
realm.write(() => {
car1 = realm.create(Car, {
make: "Nissan",
model: "Sentra",
miles: 1000,
});
});

Realm 对象中的每个属性都有一个明确定义的数据类型。属性的类型可以是原始数据类型,也可以是在同一个 Realm 中定义的对象类型。类型还指定了属性是包含单个值还是包含值的列表。

Realm 支持以下原始数据类型:

要指定字段包含原始值类型的列表,请在类型名称后面添加 []

要定义对象类型的属性,请在properties字段下创建表示属性名称和数据类型的键值对。

以下模式定义了具有以下属性的 Car 类型:_id makemodelmiles

class Car extends Realm.Object {
static schema = {
name: "Car",
properties: {
_id: { type: "objectId", default: () => new Realm.BSON.ObjectId() },
make: "string",
model: "string",
miles: "int?",
},
primaryKey: "_id",
};
}

若要将属性标记为可选属性,请在属性类型后附加一个问号 ?

以下 Car 模式定义了类型为 int 的可选 miles 属性。

class Car extends Realm.Object {
static schema = {
name: "Car",
properties: {
_id: { type: "objectId", default: () => new Realm.BSON.ObjectId() },
make: "string",
model: "string",
miles: "int?",
},
primaryKey: "_id",
};
}

要将某个属性指定为对象类型的主键,请将模式的 primaryKey 字段设置为属性名称。

注意

主键是唯一标识对象的属性。 Realm 会自动为主键属性建立索引,这样您就可以根据主键高效地读取和修改对象。

如果某个对象类型具有主键,则该类型的所有对象都必须包含主键属性,并且在 Realm 中相同类型的对象中,该主键属性具有唯一值。一个对象类型只能有一个主键。将某个对象类型的任何对象添加到 Realm 后,您无法更改该对象类型的主键属性,也无法修改对象的主键值。

以下 Car 对象模式将 _id 属性指定为其主键。

class Car extends Realm.Object {
static schema = {
name: "Car",
properties: {
_id: { type: "objectId", default: () => new Realm.BSON.ObjectId() },
make: "string",
model: "string",
miles: "int?",
},
primaryKey: "_id",
};
}

Realm 支持为字符串、整数、布尔值、DateUUIDObjectId 属性建立索引。要为给定属性定义索引,请将 indexed 设置为 true

注意

索引显著提高了某些读取操作的速度,但代价是写入速度略微下降,并增加了存储和内存开销。Realm 将索引存储在磁盘上,这会使您的 Realm 文件更大。每个索引条目至少有 12 个字节。索引条目的排序支持高效的相等匹配和基于范围的查询操作。

最好只在针对特定情况优化读取性能时添加索引。

以下 Car 对象模式定义了 _id 属性的索引。

class Car extends Realm.Object {
static schema = {
name: "Car",
properties: {
_id: { type: "objectId", indexed: true },
make: "string",
model_name: { type: "string", mapTo: "modelName" },
miles: { type: "int", default: 0 },
},
primaryKey: "_id",
};
}

除了标准索引外,Realm 还支持对字符串属性创建 Atlas 全文搜索索引。虽然无论是否使用标准索引都可以查询字符串字段,但 FTS 索引支持搜索多个词汇和短语并排除其他。

有关查询 FTS 索引的更多信息,请参阅使用全文搜索进行筛选

要创建 FTS 索引,请将索引类型设置为'full-text' 。 这将启用对该属性的全文查询。 在以下示例中,我们将name属性的索引类型设置为'full-text'

class Book extends Realm.Object<Book> {
name!: string;
price?: number;
static schema: ObjectSchema = {
name: "Book",
properties: {
name: { type: "string", indexed: "full-text" },
price: "int?",
},
};
}

要定义默认值,请将属性值设置为具有 type 字段和 default 字段的对象。

以下 Car 对象模式将 miles 属性的默认值指定为 0

class Car extends Realm.Object {
static schema = {
name: "Car",
properties: {
_id: { type: "objectId", indexed: true },
make: "string",
model_name: { type: "string", mapTo: "modelName" },
miles: { type: "int", default: 0 },
},
primaryKey: "_id",
};
}

默认情况下,Realm 在内部使用模型类中定义的名称来表示类和字段。在某些情况下,您可能想要更改此行为。例如:

  • 要便于在具有不同命名约定的多个平台上工作。例如,如果 Device Sync 模式属性名称使用蛇形大小写,而项目使用驼峰大小写。

  • 在不强制迁移的情况下更改类名或字段名。

  • 支持不同数据包中的多个同名模型类。

  • 要使用长度大于 Realm 执行的 57 个字符限制的类名。

您可以将代码中的类或属性名称映射到不同名称以存储在 Realm 中。如果写入同步 Realm,则同步模式会看到使用持久类或属性名称存储的值。

请注意,迁移必须使用持久化类或属性名称,任何模式错误报告也必须使用持久化名称。

要在代码中使用不同于 Realm 中存储的类名:

  1. 将 Realm 对象模式name 属性设置为用于存储该对象的名称。

  2. 打开 Realm 时,请使用 Realm 配置的 schema 属性中的名称。

  3. 在执行 CRUD 操作或定义灵活同步订阅时使用映射名称。

在以下示例中,Realm 将使用 Task 类创建的对象存储为 Todo_Item

class Task extends Realm.Object {
static schema = {
// Set the schema's `name` property to the name you want to store.
// Here, we store items as `Todo_Item` instead of the class's `Task` name.
name: "Todo_Item",
properties: {
_id: "int",
name: "string",
owner_id: "string?",
},
primaryKey: "_id",
};
}
const config = {
// Use the class name in the Configuration's `schema` property when
// opening the realm.
schema: [Task],
sync: {
user: anonymousUser,
flexible: true,
initialSubscriptions: {
update: (subs, realm) => {
subs.add(
realm
// Use the mapped name in Flexible Sync subscriptions.
.objects(`Todo_Item`)
.filtered(`owner_id == "${anonymousUser.id}"`)
);
},
},
},
};
const realm = await Realm.open(config);
realm.write(() => {
// Use the mapped name when performing CRUD operations.
realm.create(`Todo_Item`, {
_id: 12342245,
owner_id: anonymousUser.id,
name: "Test the Todo_Item object name",
});
});
// Use the mapped name when performing CRUD operations.
const assignedTasks = realm.objects(`Todo_Item`);
class Task extends Realm.Object<Task> {
_id!: number;
name!: string;
owner_id?: string;
static schema: ObjectSchema = {
// Set the schema's `name` property to the name you want to store.
// Here, we store items as `Todo_Item` instead of the class's `Task` name.
name: "Todo_Item",
properties: {
_id: "int",
name: "string",
owner_id: "string?",
},
primaryKey: "_id",
};
}
const config: Realm.Configuration = {
// Use the class name in the Configuration's `schema` property when
// opening the realm.
schema: [Task],
sync: {
user: anonymousUser,
flexible: true,
initialSubscriptions: {
update: (subs, realm) => {
subs.add(
realm
// Use the mapped name in Flexible Sync subscriptions.
.objects(`Todo_Item`)
.filtered(`owner_id == "${anonymousUser.id}"`)
);
},
},
},
};
const realm = await Realm.open(config);
realm.write(() => {
// Use the mapped name when performing CRUD operations.
realm.create(`Todo_Item`, {
_id: 12342245,
owner_id: anonymousUser.id,
name: "Test the Todo_Item object name",
});
});
// Use the mapped name when performing CRUD operations.
const assignedTasks = realm.objects(`Todo_Item`);

要在代码中使用不同于域中存储的属性名称,请将mapTo设立为代码中显示的属性名称。

在以下Car对象模式中, Realm使用蛇形命名法model_name属性存储汽车的模型名称。 对于客户端代码中使用的对象,该模式会将属性映射到modelName

class Car extends Realm.Object {
static schema = {
name: "Car",
properties: {
_id: { type: "objectId", indexed: true },
make: "string",
model_name: { type: "string", mapTo: "modelName" },
miles: { type: "int", default: 0 },
},
primaryKey: "_id",
};
}

提示

另请参阅:

或者,您可以在 App Services 应用程序中定义关系

对一关系将一个属性映射到另一种对象类型的单个实例。例如,您可以将最多拥有一款汽车的制造商建模为对一关系。

要定义一对一关系属性,请将相关对象类型名称指定为属性类型。

重要

对一关系必须是可选的

在对象模型中声明对一关系时,它必须是一个可选属性。如果您尝试建立所需的对一关系,Realm 会在运行时引发异常。

以下 Manufacturer 对象模式指定制造商可以生产或不生产单个 Car。如果他们生产了 Car,Realm 会通过 car 属性与之链接:

class Manufacturer extends Realm.Object {
static schema = {
name: "Manufacturer",
properties: {
_id: "objectId",
// A manufacturer that may have one car
car: "Car?",
},
};
}
class Car extends Realm.Object {
static schema = {
name: "Car",
properties: {
_id: "objectId",
make: "string",
model: "string",
miles: "int?",
},
};
}

对多关系将一个属性映射到另一种对象类型的零个或多个实例。例如,您可以将拥有任意款数汽车的制造商建模为对多关系。

要定义对多关系属性,请以列表形式指定相关对象类型名称。

应用程序可以使用以下对象模式来指示 Manufacturer 可以通过在其 cars 属性中包含多个 Car 对象来创建多个 Car 对象:

class Manufacturer extends Realm.Object {
static schema = {
name: "Manufacturer",
properties: {
_id: "objectId",
// A manufacturer that may have many cars
cars: "Car[]",
},
};
}
class Car extends Realm.Object {
static schema = {
name: "Car",
properties: {
_id: "objectId",
make: "string",
model: "string",
miles: "int?",
},
};
}

反向关系属性是一种自动反向链接关系。每当在对应的一对多列表中添加或删除对象时,Realm都会自动更新隐式关系。无法手动设置反向关系属性的值。

要定义反向关系属性,请将属性类型设为 linkingObjects,并指定定义待反向关系的对象类型和属性名称。

应用程序可以使用以下对象模式表示,Manufacturer 可以生成多个 Car 对象,每个 Car 都应自动追踪由哪个 Manufacturer 生成。

  • Manufacturer 对象的 cars 属性被定义为对多关系
    包含 Car 对象,并包含给定制造商的所有汽车。
  • Car 对象的 assignee 属性会反转此关系并
    自动更新以重新引用在其 cars 属性中包含汽车的任何 Manufacturer 对象。
class Manufacturer extends Realm.Object {
static schema = {
name: "Manufacturer",
properties: {
_id: "objectId",
// A manufacturer that may have many cars
cars: "Car[]",
},
};
}
class Car extends Realm.Object {
static schema = {
name: "Car",
properties: {
_id: "objectId",
make: "string",
model: "string",
miles: "int?",
// Backlink to the manufacturer. This is automatically updated whenever
// this car is added to or removed from a manufacturer's cars list.
assignee: {
type: "linkingObjects",
objectType: "Manufacturer",
property: "cars",
},
},
};
}

要定义具有嵌入式对象(嵌套 Realm 对象)的 Realm 对象模型,请将 embedded 设置为 true

嵌入式对象将作为单个特定父对象内部的嵌套数据而存在。它会继承父对象的生命周期,但无法作为独立 Realm 对象存在。如果某个嵌入式对象的父对象被删除或被新的嵌入式对象实例覆盖,Realm 则会自动删除该嵌入式对象。嵌入式对象无法具备主键。

可以使用与关系相同的方式从父对象类型引用嵌入式对象类型。

以下示例需要两个父模式,即 ManufacturerCar。应用程序需要嵌入式子模式 WarrantyManufacturer 对象可以嵌入 Warranty 对象列表,而 Car 对象只能嵌入单个 Warranty 对象。

class Manufacturer extends Realm.Object {
static schema = {
name: "Manufacturer",
properties: {
_id: "objectId",
name: "string",
// Embed an array of objects
warranties: { type: "list", objectType: "Warranty" },
},
};
}
class Car extends Realm.Object {
static schema = {
name: "Car",
properties: {
_id: "objectId",
make: "string",
model: "string",
miles: "int?",
// Embed one object
warranty: "Warranty",
},
};
}
class Warranty extends Realm.Object {
static schema = {
name: "Warranty",
embedded: true,
properties: {
name: "string",
termLength: "int",
cost: "int",
},
};
}

在版本 12.2.1 中进行了更改

如果您使用 Flexible Sync 并且需要将集合从设备单向同步到 Atlas 数据库,则可以在对象模式上设置 asymmetric 属性。

class WeatherSensor extends Realm.Object {
static schema = {
name: "WeatherSensor",
// Sync WeatherSensor objects one way from your device
// to your Atlas database.
asymmetric: true,
primaryKey: "_id",
properties: {
_id: "objectId",
deviceId: "string",
temperatureInFahrenheit: "int",
barometricPressureInHg: "float",
windSpeedInMph: "float",
},
};
}
class WeatherSensor extends Realm.Object<WeatherSensor> {
_id!: Realm.BSON.ObjectId;
deviceId!: string;
temperatureInFahrenheit!: number;
barometricPressureInHg!: number;
windSpeedInMph!: number;
static schema: ObjectSchema = {
name: "WeatherSensor",
// sync WeatherSensor objects one way from your device
// to your Atlas database.
asymmetric: true,
primaryKey: "_id",
properties: {
_id: "objectId",
deviceId: "string",
temperatureInFahrenheit: "int",
barometricPressureInHg: "float",
windSpeedInMph: "float",
},
};
}

在 Node.js SDK 版本 12.2.0 及更早版本中,您无法从非对称对象链接到 Realm.Object 类型。在 SDK 版本 12.2.1 及更高版本中,除了嵌入式对象以外,非对称对象还可以链接到 Realm.Object 类型。

注意

尝试读取非对称对象

无法读取非对称对象。如果尝试查询非对称对象,您将收到以下错误:“错误:无法查询非对称类。”

要了解有关数据导入的更多信息,请阅读使用数据导入优化同步。

12.9.0版本新增

从Node.js SDK版本12.9.0开始, 您可以在mixed属性中存储混合数据的集合。 您可以使用此功能对复杂的数据结构(例如JSON或MongoDB文档)进行建模,而无需定义严格的数据模型。

非结构化数据是指不容易符合预期模式的数据,因此对单个数据类进行建模很困难或不切实际。 示例,您的应用可能具有高度可变的数据或动态数据,其结构在运行时未知。

将集合存储在混合属性中可在不牺牲功能的情况下提供灵活性,包括使用Device Sync时的性能同步。 您可以像使用非混合集合一样使用它们:

  • 您最多可以嵌套100级混合集合。

  • 您可以对混合集合的React进行查询和响应。

  • 您可以查找并更新单个混合集合元素。

但是,与使用结构化模式或将JSON blob 序列化为单个string属性相比,在混合集合中存储数据的性能较低。

要对应用中的非结构化数据进行建模,请在模式中将适当的属性定义为混合类型。 然后,您可以设立这些mixed属性设置为混合元素的列表字典集合。 请注意, mixed不能表示设立或嵌入式对象。

提示

  • 当类型未知但每个值都有唯一标识符时,请使用混合数据类型的映射。

  • 当类型未知但对象的顺序有意义时,请使用混合数据类型的列表。

后退

模型数据