Define an SDK Object Model
On this page
- Object Types and Schemas
- Database Schema
- Object Model
- Object Schema
- Define an SDK Object Model
- Define Models for Specific Object Types
- Define a Realm Object
- Define an Embedded Object
- Define an Asymmetric Object
- Define a Geospatial Object
- Define Property Behaviors
- Index a Property
- Enable Full-Text Search on a Property
- Designate a Primary Key
- Define an Optional Property
- Ignore a Property
- Set a Default Value for a Property
- Define Custom Setters
- Model Unstructured Data
- Map a Model or Property to a Different Name
- Transform Model Data for View Models
- Transform Persisted Properties
- Define a Projection
Atlas Device SDK applications model data as objects composed of field-value pairs that each contain one or more supported data types. You can annotate a property to provide additional meta-information that gives the property special behaviors, such as:
Designate a property as the object's primary key
Ignore a property when reading and writing data
Index a property to improve performance for queries on that property
Index a property for use with Full-Text Search
Map a property or class to a different stored name
Object Types and Schemas
Every database object has an object type that refers to the object's class or struct. Objects of the same type share an object schema that defines the properties and relationships of those objects.
Database Schema
A database schema is a list of valid object schemas that the database may contain. Every database object must conform to an object type that's included in its database's schema.
In C++, when opening a database, you must specify which models are available by passing the models to the template you use to open the database. Those models must have schemas, and this list of schemas becomes the database schema.
In C#, you can define object schemas by using the C# class declarations. When a database is initialized, it discovers the SDK objects defined in all assemblies that have been loaded and generates schemas accordingly. If you want to restrict a database to manage only a subset of the SDK models in the loaded assemblies, you can explicitly pass the models when configuring a database.
For more information, refer to Provide a Subset of Models to a Database.
Note
.NET does not load an assembly until you reference a class in it. If you define your object models in one assembly and instantiate a database in another, be sure to call a method in the assembly that contains the object models before initialization. Otherwise, the SDK does not discover the objects when it first loads.
In Dart, the database configuration takes a RealmSchema that has an iterable collection of
SchemaObjects. These
SchemaObjects
represent the SDK object types that the database file can
manage.
In Java, the SDK automatically adds all classes in your project that derive from an SDK object type to the database schema.
The JS SDK's database configuration
has a schema
property that takes an array of object schemas that the
database instance can manage.
In Kotlin, the database configuration has a schema property that takes a set of classes that the database can manage.
In Java, the SDK automatically adds all classes in your project that derive from an SDK object type to the database schema.
In Objective-C, you don't have to explicitly specify the database schema when you configure the database. Swift SDK executables can automatically read and write any valid SDK object whose model is included in the executable. If you want to restrict a database to manage only a subset of the SDK models in the executable, you can explicitly pass the models when configuring a database.
For more information, refer to Provide a Subset of Models to a Database.
In Swift, you don't have to explicitly specify the database schema when you configure the database. Swift SDK executables can automatically read and write any valid SDK object whose model is included in the executable. If you want to restrict a database to manage only a subset of the SDK models in the executable, you can explicitly pass the models when configuring a database.
For more information, refer to Provide a Subset of Models to a Database.
The JS SDK's database configuration
has a schema
property that takes an array of object schemas that the
database instance can manage.
If the database already contains data when you open it, the SDK validates each object to ensure that an object schema was provided for its type and that it meets all of the constraints specified in the schema.
For more information about how to open the database, refer to Configure & Open a Database File.
Object Model
Your object model is the core structure that gives the database information about how to interpret and store the objects in your app. The properties that you want to persist must use the supported data types. Properties are also the mechanism for establishing relationships between object types, or establishing other special behaviors for specific fields in your object.
The C++ SDK object model is a regular C++ class or struct that contains a collection of properties. When you define your C++ class or struct, you must also provide an object schema. The schema is a C++ macro that gives the SDK information about which properties to persist, and what type of database object it is.
You must define your SDK object model within the realm
namespace.
In C#, SDK object models are regular C# classes that define the SDK data model.
In Dart, you can define the object model using the native class implementation. You must annotate the class model with the SDK object type definition. As a separate step, you must generate SDK object classes that contain additional methods and meta-information that makes it possible to store, retrieve, and work with the object.
In the Java SDK, unlike normal Java objects, which contain their own data, an SDK object doesn't contain data. Instead, SDK objects read and write properties directly to the database.
The Java SDK uses RealmProxy
classes to ensure that database objects
don't contain any data themselves. Instead, each class's RealmProxy
accesses data directly in the database.
For every model class in your project, the SDK annotation processor generates
a corresponding RealmProxy
class. This class extends your model class and
is returned when you call Realm.createObject()
. In your code, this object
works just like your model class.
Java SDK Object Limitations
SDK objects:
cannot contain fields that use the
final
orvolatile
modifiers (except for inverse relationship fields).cannot extend any object other than
RealmObject
.must contain an empty constructor (if your class does not include any constructor, the automatically generated empty constructor will suffice)
Usage limitations:
Because SDK objects are live and can change at any time, their
hashCode()
value can change over time. As a result, you should not useRealmObject
instances as a key in any map or set.
Java SDK Incremental Builds
The bytecode transformer used by the Java SDK supports incremental builds, but your application requires a full rebuild when adding or removing the following from an SDK object field:
an
@Ignore
annotationthe
static
keywordthe
transient
keyword
You can perform a full rebuild with Build > Clean Project and Build > Rebuild Project in these cases.
You can define SDK models as JavaScript classes that extend Realm.Object
.
When you create objects, use an object literal. This lets you create an unmanaged object, and pass it to the database when it makes sense to do so.
Do not use new
to construct a new object instance. If you use new
with
class-based models, this creates a new managed object, which has the
following side effects:
Constructing a
new
object calls therealm.create()
method, which can only be used in a write transcation.Constructing a
new
object has complications when the object contains or is itself an embedded object.
For more information about object creation and managed objects, refer to Create Objects and Create Specific Object Types.
In the Kotlin SDK, you define your application's data model with regular Kotlin classes declared in your application code.
In the Java SDK, unlike normal Java objects, which contain their own data, an SDK object doesn't contain data. Instead, SDK objects read and write properties directly to the database.
The Java SDK uses RealmProxy
classes to ensure that database objects
don't contain any data themselves. Instead, each class's RealmProxy
accesses data directly in the database.
For every model class in your project, the SDK annotation processor generates
a corresponding RealmProxy
class. This class extends your model class and
is returned when you call Realm.createObject()
. In your code, this object
works just like your model class.
Java SDK Object Limitations
SDK objects:
cannot contain fields that use the
final
orvolatile
modifiers (except for inverse relationship fields).cannot extend any object other than
RealmObject
.must contain an empty constructor (if your class does not include any constructor, the automatically generated empty constructor will suffice)
Usage limitations:
Because SDK objects are live and can change at any time, their
hashCode()
value can change over time. As a result, you should not useRealmObject
instances as a key in any map or set.
Java SDK Incremental Builds
The bytecode transformer used by the Java SDK supports incremental builds, but your application requires a full rebuild when adding or removing the following from an SDK object field:
an
@Ignore
annotationthe
static
keywordthe
transient
keyword
You can perform a full rebuild with Build > Clean Project and Build > Rebuild Project in these cases.
In Objective-C, SDK object models are regular Objective-C classes that define the SDK data model.
Objective-C SDK objects must derive from one of the SDK object types.
Model Inheritance
You can subclass SDK models to share behavior between classes, but there are limitations. In particular, the SDK does not allow you to:
Cast between polymorphic classes: subclass to subclass, subclass to parent, parent to subclass
Query on multiple classes simultaneously: for example, "get all instances of parent class and subclass"
Multi-class containers:
List
andResults
with a mixture of parent and subclass
Tip
Check out the code samples for working around these limitations.
In Swift, SDK object models are regular Swift classes that define the SDK data model.
Swift SDK objects must derive from one of the SDK object types.
Model Inheritance
You can subclass SDK models to share behavior between classes, but there are limitations. In particular, the SDK does not allow you to:
Cast between polymorphic classes: subclass to subclass, subclass to parent, parent to subclass
Query on multiple classes simultaneously: for example, "get all instances of parent class and subclass"
Multi-class containers:
List
andResults
with a mixture of parent and subclass
Tip
Check out the code samples for working around these limitations.
Swift Structs
The SDK does not support Swift structs as models for a variety of reasons. The SDK's design focuses on "live" objects. This concept is not compatible with value-type structs. By design, the SDK provides features that are incompatible with these semantics, such as:
Low memory footprint of data
Good operation performance
Lack of data serialization/deserialization
That said, it is sometimes useful to detach objects from their backing database. This typically isn't an ideal design decision. Instead, developers use this as a workaround for temporary limitations in our library.
You can use key-value coding to initialize an unmanaged object as a copy of a managed object. Then, you can work with that unmanaged object like any other NSObject.
let standaloneModelObject = MyModel(value: persistedModelObject)
You can define SDK models as TypeScript classes that extend Realm.Object
.
When you create objects, use an object literal. This lets you create an unmanaged object, and pass it to the database when it makes sense to do so.
Do not use new
to construct a new object instance. If you use new
with
class-based models, this creates a new managed object, which has the
following side effects:
Constructing a
new
object calls therealm.create()
method, which can only be used in a write transcation.Constructing a
new
object has complications when the object contains or is itself an embedded object.
For more information about object creation and managed objects, refer to Create Objects and Create Specific Object Types.
Object Schema
An object schema maps properties for a specific object type. The SDK schemas give the SDK the information it needs to validate, store, and retrieve the objects. A schema must accompany every object model you want to persist. When possible, Device SDK uses language-specific features to simplify or abstract away the process of creating a schema.
In C++, schemas are managed through macros. The schema must list every property type that you want to persist. The SDK inspects the object model to determine the property types and other special information, such as whether a property is the object's primary key.
A schema must accompany every object model you want to persist, and it may be one of:
REALM_SCHEMA
REALM_EMBEDDED_SCHEMA
REALM_ASYMMETRIC_SCHEMA
You must define the schema and your object model within the realm
namespace.
In C#, when the SDK processes SDK object types, it generates a schema for each class based on the class properties. However, there may be times that you want to manually define the schema, and the .NET SDK provides a mechanism for doing so.
In Dart, the object schema is automatically generated as part of the SDK object
model code generation step. You can view the schema as a static final schema
property in the generated .realm.dart
file.
In the Java SDK, the SDK automatically creates object schemas based on your SDK model classes.
When you create an SDK object model class, you define the type's name
and
properties
in a static property called schema
.
When the SDK model extends Realm.Object
, you pass the model class directly
to the database schema
list, and it uses the schema
property in your
model class as a part of the database schema.
When the SDK model does not extend Realm.Object
, as when it is an
embedded object, you pass only the object's schema to the database schema
list. You cannot pass the object itself directly to the database.
In the Kotlin SDK, you do not need to manually specify an object schema. The
SDK automatically creates an object schema for every object type that inherits
from the RealmObject
class or its subclasses: EmbeddedRealmObject
or
AsymmetricRealmObject
.
In the Java SDK, the SDK automatically creates object schemas based on your SDK model classes.
The Swift SDK does not require you to manually create object schemas. Instead, it uses reflection to automatically create schemas for your SDK object types.
Your project must not set
SWIFT_REFLECTION_METADATA_LEVEL = none
, or the SDK cannot discover
properties in your models. Reflection is enabled by default if your project
does not specifically set a level for this setting.
The Swift SDK does not require you to manually create object schemas. Instead, it uses reflection to automatically create schemas for your SDK object types.
Your project must not set
SWIFT_REFLECTION_METADATA_LEVEL = none
, or the SDK cannot discover
properties in your models. Reflection is enabled by default if your project
does not specifically set a level for this setting.
When you create an SDK object model class, you define the type's name
and
properties
in a static property called schema
.
When the SDK model extends Realm.Object
, you pass the model class directly
to the database schema
list, and it uses the schema
property in your
model class as a part of the database schema.
When the SDK model does not extend Realm.Object
, as when it is an
embedded object, you pass only the object's schema to the database schema
list. You cannot pass the object itself directly to the database.
Define an SDK Object Model
In the C++ SDK, you can define your models as regular C++ structs or classes. Provide an Object Schema with the object type name and the names of any properties that you want to persist to the database. When you add the object to the database, the SDK ignores any properties that you omit from the schema.
You must declare your object and the schema within the realm
namespace.
You must then use the realm
namespace when you initialize and perform CRUD
operations with the object.
All SDK objects inherit from the
IRealmObject,
IEmbeddedObject, or
IAsymmetricObject
interface and must be declared partial
classes.
In versions of the .NET SDK v10.18.0 and earlier, objects derive from RealmObject, EmbeddedObject, or AsymmetricObject base classes. This approach to SDK model definition is still supported, but does not include new features such as the nullability annotations. These base classes will be deprecated in a future SDK release. You should use the interfaces for any new classes that you write and should consider migrating your existing classes.
public partial class Dog : IRealmObject { [ ] [ ] public ObjectId Id { get; set; } public string Name { get; set; } public int Age { get; set; } public string Breed { get; set; } public IList<Person> Owners { get; } } public partial class Person : IRealmObject { [ ] [ ] public ObjectId Id { get; set; } public string Name { get; set; } // etc... /* To add items to the IList<T>: var dog = new Dog(); var caleb = new Person { Name = "Caleb" }; dog.Owners.Add(caleb); */ }
Customize the Object Schema (Optional)
You can use the Schema property of the RealmConfigurationBase object to customize how schemas are defined. The following code example shows three ways to do this, from easiest to most complex:
Automatic configuration
Manual configuration
A mix of both methods
Create Generated File Part Directive
Changed in version v2.0.0: Generated files are named
.realm.dart
instead of.g.dart
Add a part directive to include the
RealmObject
file that you generate in step 4 in the same package as the file you're currently working on.modelFile.dartpart 'modelFile.realm.dart'; Create a
RealmModel
.Create the model for your SDK object type. You must include the annotation RealmModel at the top of the class definition.
You'll use the
RealmModel
to generate the publicRealmObject
used throughout the application in step 4.You can make the model private or public. We recommend making all models private and defining them in a single file. Prepend the class name with an underscore (
_
) to make it private.If you need to define your schema across multiple files, you can make the
RealmModel
public. Prepend the name with a dollar sign ($
) to make the model public. You must do this to generate theRealmObject
from theRealmModel
, as described in step 4.Add fields to the
RealmModel
. You can add fields of any supported data types. Include additional behavior using special object types.modelFile.dart() class _Car { late ObjectId id; late String make; late String? model; late int? miles; } Generate a
RealmObject
.Changed in version v2.0.0: Generated files are named
.realm.dart
instead of.g.dart
Generate the
RealmObject
, which you'll use in your application:dart run realm generate dart run realm_dart generate This command generates the file in the same directory as your model file. It has the name you specified in the part directive of step 2.
Tip
Track the generated file
Track the generated file in your version control system, such as git.
Example
File structure after generating model
. ├── modelFile.dart ├── modelFile.realm.dart // newly generated file ├── myapp.dart └── ...rest of application Use the
RealmObject
in your application code.Use the
RealmObject
that you generated in the previous step in your application code. Since you included the generated file as part of the same package where you defined theRealmModel
in step 2, access theRealmObject
by importing the file with theRealmModel
.
In Java, to define an SDK object in your application, create a subclass of RealmObject or implement RealmModel.
Important
All SDK objects must provide an empty constructor.
All SDK objects must use the
public
visibility modifier
Extend RealmObject
The following code block shows a Realm object that
describes a Frog. This Frog class can be stored in the database because it
extends
the RealmObject
class.
import io.realm.RealmObject; // To add an object to your Realm Schema, extend RealmObject public class Frog extends RealmObject { private String name; private int age; private String species; private String owner; public Frog(String name, int age, String species, String owner) { this.name = name; this.age = age; this.species = species; this.owner = owner; } public Frog(){} // RealmObject subclasses must provide an empty constructor public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSpecies() { return species; } public void setSpecies(String species) { this.species = species; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } }
Implement RealmModel
The following code block shows a Realm object that
describes a Frog. This Frog class can
be stored in the database because it implements
the
RealmModel
class and uses the @RealmClass
annotation:
import io.realm.RealmModel; import io.realm.annotations.RealmClass; public class Frog implements RealmModel { private String name; private int age; private String species; private String owner; public Frog(String name, int age, String species, String owner) { this.name = name; this.age = age; this.species = species; this.owner = owner; } public Frog() {} // RealmObject subclasses must provide an empty constructor public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSpecies() { return species; } public void setSpecies(String species) { this.species = species; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } }
Important
All Realm objects must use the public
visibility modifier.
Tip
Using RealmObject Methods
When you create a Realm object by extending the RealmObject
class, you can access RealmObject
class methods dynamically on
instances of your Realm object. Realm objects
created by implementing RealmModel
can access those same methods
statically through the RealmObject
class.
In JavaScript, to define an SDK object, create a JavaScript class that extends Realm.Object.
Define a static schema
object that includes a name
property and
a properties
array. The name
becomes the table name in the database.
The properties
array describes the property names, types, and any additional
details about special property behaviors, such as whether the property should
be indexed.
For object types with special behaviors, such as embedded objects and
asymmetric objects, set the optional embedded
or asymmetric
property
to true
.
In the Kotlin SDK, define an SDK object as a Kotlin class. Each object class represents an object type.
SDK objects must inherit from the RealmObject
class or its
subclasses: EmbeddedRealmObject
or AsymmetricRealmObject
.
The Kotlin SDK does not support inheritance from custom base classes.
Additionally, the Kotlin SDK does not support using Kotlin data classes to model data. This is because data classes are typically used for immutable data, which goes against how the Kotlin SDK models data.
Kotlin SDK Requires an Empty Constructor
The Kotlin SDK requires that SDK objects have an empty constructor.
If you cannot provide an empty constructor, as a workaround, you can do something similar to the following:
class Person(var name: String, var age: Int): RealmObject { constructor(): this("", 0) // Empty constructor required by the SDK }
Using Kotlin in the Java SDK, to define an SDK object in your application, create a subclass of RealmObject or implement RealmModel.
Important
All SDK objects must provide an empty constructor.
All SDK objects must use the
open
visibility modifier.
Extend RealmObject
The following code block shows an SDK object that
describes a Frog. This Frog class can be stored in
the database because it extends
the RealmObject
class.
import io.realm.RealmObject // providing default values for each constructor parameter // fulfills the need for an empty constructor open class Frog( var name: String? = null, var age: Int = 0, var species: String? = null, var owner: String? = null ) : RealmObject() // To add an object to your Realm Schema, extend RealmObject
Implement RealmModel
The following code block shows an SDK object that
describes a Frog. This Frog class can
be stored in the database because it implements
the
RealmModel
class and uses the @RealmClass
annotation:
import io.realm.RealmModel import io.realm.annotations.RealmClass open class Frog : RealmModel { var name: String? = null var age = 0 var species: String? = null var owner: String? = null constructor(name: String?, age: Int, species: String?, owner: String?) { this.name = name this.age = age this.species = species this.owner = owner } constructor() {} // RealmObject subclasses must provide an empty constructor }
Tip
Using RealmObject Methods
When you create a Realm object by extending the RealmObject
class, you can access RealmObject
class methods dynamically on
instances of your Realm object. Realm objects
created by implementing RealmModel
can access those same methods
statically through the RealmObject
class.
In Objective-C, to define an SDK object, create a class that inherits from one of the SDK object types:
The name of the class becomes the table name in the database. Properties of the class persist in the database. This makes it as easy to work with persisted objects as it is to work with regular Objective-C objects.
In Swift, to define an SDK object, create a class that inherits from one of the SDK object types:
The name of the class becomes the table name in the database. Properties of the class persist in the database. This makes it as easy to work with persisted objects as it is to work with regular Swift objects.
In TypeScript, to define an SDK object, create a TypeScript class that extends Realm.Object.
Define a static schema
object that includes a name
property and
a properties
array. The name
becomes the table name in the database.
The properties
array describes the property names, types, and any additional
details about special property behaviors, such as whether the property should
be indexed.
For object types with special behaviors, such as embedded objects and
asymmetric objects, set the optional embedded
or asymmetric
property
to true
.
namespace realm { struct Dog { std::string name; int64_t age; }; REALM_SCHEMA(Dog, name, age) struct Person { realm::primary_key<int64_t> _id; std::string name; int64_t age; // Create relationships by pointing an Object field to another struct or class Dog *dog; }; REALM_SCHEMA(Person, _id, name, age, dog) } // namespace realm
// By default, all loaded RealmObject classes are included. // Use the RealmConfiguration when you want to // construct a schema for only specific C# classes: var config = new RealmConfiguration { Schema = new[] { typeof(ClassA), typeof(ClassB) } }; // More advanced: construct the schema manually var manualConfig = new RealmConfiguration { Schema = new RealmSchema.Builder { new Builder("ClassA", ObjectType.EmbeddedObject) { Property.Primitive("Id", RealmValueType.Guid, isPrimaryKey: true), Property.Primitive("LastName", RealmValueType.String, isNullable: true, indexType: IndexType.General) } } }; // Most advanced: mix and match var mixedSchema = new ObjectSchema.Builder(typeof(ClassA)); mixedSchema.Add(Property.FromType<int>("ThisIsNotInTheCSharpClass")); // `mixedSchema` now has all of the properties of the ClassA class // and an extra integer property called "ThisIsNotInTheCSharpClass" var mixedConfig = new RealmConfiguration { Schema = new[] { mixedSchema.Build() } };
import './schemas.dart'; final hondaCivic = Car(ObjectId(), 'Honda', model: 'Civic', miles: 99);
// With RealmObject frogRealmObject.isValid(); frogRealmObject.addChangeListener(listener); // With RealmModel RealmObject.isValid(frogRealmModel); RealmObject.addChangeListener(frogRealmModel, listener);
class Book extends Realm.Object { static schema = { name: 'Book', properties: { name: {type: 'string', indexed: true}, price: 'int?', }, }; }
// Implements the `RealmObject` interface class Frog : RealmObject { // Empty constructor required by Realm var _id: ObjectId = ObjectId() var name: String = "" var age: Int = 0 var species: String? = null var owner: String? = null }
// With RealmObject frogRealmObject?.isValid frogRealmObject?.addChangeListener(listener) // With RealmModel RealmObject.isValid(frogRealmModel) RealmObject.addChangeListener(frogRealmModel, listener)
// A dog has an _id primary key, a string name, an optional // string breed, and a date of birth. @interface Dog : RLMObject @property RLMObjectId *_id; @property NSString *name; @property NSString *breed; @property NSDate *dateOfBirth; @end @implementation Dog + (NSString *)primaryKey { return @"_id"; } + (NSArray<NSString *> *)requiredProperties { return @[ @"_id", @"name", @"dateOfBirth" ]; } @end
// A dog has an _id primary key, a string name, an optional // string breed, and a date of birth. class Dog: Object { true) var _id: ObjectId (primaryKey: var name = "" var breed: String? var dateOfBirth = Date() }
class Book extends Realm.Object<Book> { name!: string; price?: number; static schema: ObjectSchema = { name: 'Book', properties: { name: {type: 'string', indexed: true}, price: 'int?', }, }; }
Note
Class names are limited to a maximum of 57 UTF-8 characters.
Define Models for Specific Object Types
The SDK provides three specific object types, plus support for using an object with geospatial data:
Realm object: the base object type used by the SDK.
Embedded object: a special object type that cannot exist outside the lifecycle of its parent Realm object.
Asymmetric object: a special object type used in heavy insert-only workloads using the Data Ingest feature.
Geospatial object: an object that uses duck-typing to provide a consistent interface and special methods for working with geospatial data.
Throughout the documentation, when we refer to "SDK objects" or "SDK object types," we refer to one of these object types.
Define a Realm Object
A Realm object is the base object type stored by the SDK's device persistence layer, Realm.
In C++, the base object provides accessors and other methods to work with SDK objects, including things like:
Checking whether an object is valid
Getting its managing database instance
Registering a notification token
Define a C++ struct or class as you would normally. Add a REALM_SCHEMA
whose first value is the name of the struct or class. Add the names of the
properties that you want the database to manage. Omit any fields that you do
not want to persist.
In C#, to define a Realm object, inherit from the the
IRealmObject interface and
declare the class a partial
class.
The following code block shows an object schema that describes a Dog.
Every Dog object must include a Name
and may
optionally include the dog's Age
, Breed
and a list of people that
represents the dog's Owners
.
In Dart, to define a Realm object, create a class model and add the
RealmModel
annotation. Follow the Define an SDK Object Model procedure detailed on this
page to generate the RealmObject
model and schema definitions.
Then, use the generated RealmObject
model in your application code.
In the Java SDK, to define a Realm object in your application, subclass RealmObject or implement RealmModel.
Create a JavaScript class that extends Realm.Object.
Define a static schema
object of type ObjectSchema. This schema includes a name
property,
which becomes the table name in the database. The schema should include a
properties
array, which is an array of objects of type
PropertiesTypes. Each object in
this array contains a string key that becomes the name of the property, and
a PropertySchema that provides
additional details about the property, such as its type and any special
behaviors it should have.
In the Kotlin SDK, to define a Realm object type, create a Kotlin class that implements the RealmObject interface.
In the Java SDK, to define a Realm object in your application, subclass RealmObject or implement RealmModel.
In Objective-C, to define a Realm object, create a class that inherits from RLMObject.
In Swift, to define a Realm object, create a class that inherits from Object.
Create a TypeScript class that extends Realm.Object.
Define a static schema
object of type ObjectSchema. This schema includes a name
property,
which becomes the table name in the database. The schema should include a
properties
array, which is an array of objects of type
PropertiesTypes. Each object in
this array contains a string key that becomes the name of the property, and
a PropertySchema that provides
additional details about the property, such as its type and any special
behaviors it should have.
namespace realm { struct Dog { std::string name; int64_t age; }; REALM_SCHEMA(Dog, name, age) struct Person { realm::primary_key<int64_t> _id; std::string name; int64_t age; // Create relationships by pointing an Object field to another struct or class Dog *dog; }; REALM_SCHEMA(Person, _id, name, age, dog) } // namespace realm
public partial class Dog : IRealmObject { [ ] [ ] public ObjectId Id { get; set; } public string Name { get; set; } public int Age { get; set; } public string Breed { get; set; } public IList<Person> Owners { get; } } public partial class Person : IRealmObject { [ ] [ ] public ObjectId Id { get; set; } public string Name { get; set; } // etc... /* To add items to the IList<T>: var dog = new Dog(); var caleb = new Person { Name = "Caleb" }; dog.Owners.Add(caleb); */ }
()class _Car { () late ObjectId id; late String make; late String? model; late int? miles; }
import './schemas.dart'; final hondaCivic = Car(ObjectId(), 'Honda', model: 'Civic', miles: 99);
import io.realm.RealmObject; // To add an object to your Realm Schema, extend RealmObject public class Frog extends RealmObject { private String name; private int age; private String species; private String owner; public Frog(String name, int age, String species, String owner) { this.name = name; this.age = age; this.species = species; this.owner = owner; } public Frog(){} // RealmObject subclasses must provide an empty constructor public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSpecies() { return species; } public void setSpecies(String species) { this.species = species; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } }
import io.realm.RealmModel; import io.realm.annotations.RealmClass; public class Frog implements RealmModel { private String name; private int age; private String species; private String owner; public Frog(String name, int age, String species, String owner) { this.name = name; this.age = age; this.species = species; this.owner = owner; } public Frog() {} // RealmObject subclasses must provide an empty constructor public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSpecies() { return species; } public void setSpecies(String species) { this.species = species; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } }
class Book extends Realm.Object { static schema = { name: 'Book', properties: { name: {type: 'string', indexed: true}, price: 'int?', }, }; }
// Implements the `RealmObject` interface class Frog : RealmObject { // Empty constructor required by Realm var _id: ObjectId = ObjectId() var name: String = "" var age: Int = 0 var species: String? = null var owner: String? = null }
import io.realm.RealmObject // providing default values for each constructor parameter // fulfills the need for an empty constructor open class Frog( var name: String? = null, var age: Int = 0, var species: String? = null, var owner: String? = null ) : RealmObject() // To add an object to your Realm Schema, extend RealmObject
import io.realm.RealmModel import io.realm.annotations.RealmClass open class Frog : RealmModel { var name: String? = null var age = 0 var species: String? = null var owner: String? = null constructor(name: String?, age: Int, species: String?, owner: String?) { this.name = name this.age = age this.species = species this.owner = owner } constructor() {} // RealmObject subclasses must provide an empty constructor }
// A dog has an _id primary key, a string name, an optional // string breed, and a date of birth. @interface Dog : RLMObject @property RLMObjectId *_id; @property NSString *name; @property NSString *breed; @property NSDate *dateOfBirth; @end @implementation Dog + (NSString *)primaryKey { return @"_id"; } + (NSArray<NSString *> *)requiredProperties { return @[ @"_id", @"name", @"dateOfBirth" ]; } @end
// A dog has an _id primary key, a string name, an optional // string breed, and a date of birth. class Dog: Object { true) var _id: ObjectId (primaryKey: var name = "" var breed: String? var dateOfBirth = Date() }
class Book extends Realm.Object<Book> { name!: string; price?: number; static schema: ObjectSchema = { name: 'Book', properties: { name: {type: 'string', indexed: true}, price: 'int?', }, }; }
Define an Embedded Object
An embedded object is a special type of object that models complex data about a specific object. Embedded objects are similar to relationships, but they provide additional constraints and map more naturally to the denormalized MongoDB document model.
The SDK enforces unique ownership constraints that treat each embedded object as nested data inside of a single, specific parent object. An embedded object inherits the lifecycle of its parent object and cannot exist as an independent database object. The SDK automatically deletes embedded objects if their parent object is deleted or when overwritten by a new embedded object instance. This differs from a to-one or to-many relationship, in which the related objects have independent lifecycles.
In C++, you define an embedded object by providing a REALM_EMBEDDED_SCHEMA
whose first argument is the struct or class name. Add the names of any
properties that you want the database to persist.
Define a property as an embedded object on the parent object by setting a pointer to the embedded object's type.
In C#, to define an embedded object, inherit from the the
IEmbeddedObject interface
and declare the class a partial
class. You can reference an embedded object
type from parent object types in the same way as you would define a relationship.
Consider the following example where the Address
is an Embedded Object. Both
the Contact
and the Business
classes reference the Address
as an
embedded object.
In Dart, to define an embedded object, create a class model and add the
RealmModel
annotation. Pass ObjectType.embeddedObject
to the @RealmModel()
annotation.
Embedded objects must be nullable when defining them in the parent object's
RealmModel
. You can use the parent property to access the parent of
the embedded object.
Follow the Define an SDK Object Model procedure detailed on this
page to generate the RealmObject
model and schema definitions.
Then, use the generated RealmObject
model in your application code.
The following example shows how to model an embedded object in a Realm object
schema. The _Address
model is embedded within the _Person
model.
To embed an object, set the embedded
property of the
@RealmClass
annotation to true
on the class that you'd like to nest within
another class:
import io.realm.RealmObject; import io.realm.annotations.RealmClass; public class Fly extends RealmObject { private String name; public Fly(String name) { this.name = name; } public Fly() {} // RealmObject subclasses must provide an empty constructor }
Then, any time you reference that class from another class, the SDK embeds the referenced class within the enclosing class, as in the following example:
In the JavaScript SDK, to define an embedded object, set embedded
to true
. You can reference an embedded object type from parent object types
in the same way as you would define a relationship.
In the Kotlin SDK, to define an embedded object type, create a Kotlin class that implements the EmbeddedRealmObject interface.
To embed an object, set the embedded
property of the
@RealmClass
annotation to true
on the class that you'd like to nest within
another class:
import io.realm.RealmObject import io.realm.annotations.RealmClass open class Fly : RealmObject { private var name: String? = null constructor(name: String?) { this.name = name } constructor() {} // RealmObject subclasses must provide an empty constructor }
Then, any time you reference that class from another class, the SDK embeds the referenced class within the enclosing class, as in the following example:
In Objective-C, to define an embedded object, create a class that inherits from RLMEmbeddedObject. You can use your embedded object in another model as you would any other type.
In Swift, to define an embedded object, create a class that inherits from EmbeddedObject. You can use your embedded object in another model as you would any other type.
In the JavaScript SDK, to define an embedded object, set embedded
to true
. You can reference an embedded object type from parent object types
in the same way as you would define a relationship.
namespace realm { struct ContactDetails { // Because ContactDetails is an embedded object, it cannot have its own _id // It does not have a lifecycle outside of the top-level object std::string emailAddress; std::string phoneNumber; }; REALM_EMBEDDED_SCHEMA(ContactDetails, emailAddress, phoneNumber) struct Business { realm::object_id _id; std::string name; ContactDetails *contactDetails; }; REALM_SCHEMA(Business, _id, name, contactDetails) } // namespace realm
public partial class Address : IEmbeddedObject { [ ] public string Street { get; set; } [ ] public string City { get; set; } [ ] public string Country { get; set; } [ ] public string PostalCode { get; set; } } public partial class Contact : IRealmObject { [ ] [ ] public ObjectId Id { get; set; } = ObjectId.GenerateNewId(); [ ] public string Partition { get; set; } [ ] public string Name { get; set; } [ ] public Address? Address { get; set; } // embed a single address } public partial class Business : IRealmObject { [ ] [ ] public ObjectId Id { get; set; } = ObjectId.GenerateNewId(); [ ] public string Partition { get; set; } [ ] public string Name { get; set; } [ ] public IList<Address> Addresses { get; } }
// The generated `Address` class is an embedded object. (ObjectType.embeddedObject)class _Address { late String street; late String city; late String state; late String country; } ()class _Person { () late ObjectId id; late String name; // Embedded object in parent object schema late _Address? address; // Must be nullable }
import io.realm.RealmObject; public class Frog extends RealmObject { private String name; private int age; private String species; private String owner; private Fly lastMeal; public Frog(String name, int age, String species, String owner, Fly lastMeal) { this.name = name; this.age = age; this.species = species; this.owner = owner; this.lastMeal = lastMeal; } public Frog(){} // RealmObject subclasses must provide an empty constructor public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSpecies() { return species; } public void setSpecies(String species) { this.species = species; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } public Fly getLastMeal() { return lastMeal; } public void setLastMeal(Fly lastMeal) { this.lastMeal = lastMeal; } }
const AddressSchema = { name: "Address", embedded: true, // default: false properties: { street: "string?", city: "string?", country: "string?", postalCode: "string?", }, }; const ContactSchema = { name: "Contact", primaryKey: "_id", properties: { _id: "objectId", name: "string", address: "Address", // Embed a single object }, }; const BusinessSchema = { name: "Business", primaryKey: "_id", properties: { _id: "objectId", name: "string", addresses: { type: "list", objectType: "Address" }, // Embed an array of objects }, };
// Implements `EmbeddedRealmObject` interface class EmbeddedAddress : EmbeddedRealmObject { // CANNOT have primary key var street: String? = null var city: String? = null var state: String? = null var postalCode: String? = null var propertyOwner: Contact? = null }
import io.realm.RealmObject open class Frog : RealmObject { var name: String? = null var age = 0 var species: String? = null var owner: String? = null var lastMeal: Fly? = null constructor( name: String?, age: Int, species: String?, owner: String?, lastMeal: Fly? ) { this.name = name this.age = age this.species = species this.owner = owner this.lastMeal = lastMeal } constructor() {} // RealmObject subclasses must provide an empty constructor }
// Define an embedded object @interface Address : RLMEmbeddedObject @property NSString *street; @property NSString *city; @property NSString *country; @property NSString *postalCode; @end // Enable Address for use in RLMArray RLM_COLLECTION_TYPE(Address) @implementation Address @end // Define an object with one embedded object @interface Contact : RLMObject @property NSString *name; // Embed a single object. @property Address *address; @end @implementation Contact @end // Define an object with an array of embedded objects @interface Business : RLMObject @property NSString *name; // Embed an array of objects @property RLMArray<Address *><Address> *addresses; @end
class Person: Object { true) var id = 0 (primaryKey: var name = "" // To-many relationship - a person can have many dogs var dogs: List<Dog> // Inverse relationship - a person can be a member of many clubs "members") var clubs: LinkingObjects<DogClub> (originProperty: // Embed a single object. // Embedded object properties must be marked optional. var address: Address? convenience init(name: String, address: Address) { self.init() self.name = name self.address = address } } class DogClub: Object { var name = "" var members: List<Person> // DogClub has an array of regional office addresses. // These are embedded objects. var regionalOfficeAddresses: List<Address> convenience init(name: String, addresses: [Address]) { self.init() self.name = name self.regionalOfficeAddresses.append(objectsIn: addresses) } } class Address: EmbeddedObject { var street: String? var city: String? var country: String? var postalCode: String? }
class Manufacturer extends Realm.Object { _id!: BSON.ObjectId; name!: string; cars!: Realm.List<CarWithEmbed>; warranties!: Realm.List<Warranty>; static schema: Realm.ObjectSchema = { name: 'Manufacturer', properties: { _id: 'objectId', name: 'string', cars: 'CarWithEmbed[]', // Embed an array of objects warranties: 'Warranty[]', }, }; } class CarWithEmbed extends Realm.Object { _id!: BSON.ObjectId; model!: string; miles?: number; warranty?: Warranty; static schema: Realm.ObjectSchema = { name: 'CarWithEmbed', properties: { _id: 'objectId', model: 'string', miles: 'int?', // Embed one object warranty: 'Warranty?', }, }; } class Warranty extends Realm.Object { name!: string; termLength!: number; cost!: number; static schema: Realm.ObjectSchema = { name: 'Warranty', embedded: true, properties: { name: 'string', termLength: 'int', cost: 'int', }, }; }
Important
Lifecycle considerations
Because embedded objects cannot exist as objects independent of their parent object, when you delete a Realm object, the SDK automatically deletes any embedded objects referenced by that object. Any objects that your application must persist after the deletion of their parent object should use relationships instead.
Additionally, embedded objects cannot have a primary key.
Define an Asymmetric Object
You can use Data Ingest to sync an object unidirectionally from your device to the database linked to your Atlas App Services App.
Asymmetric objects do not function in the same way as other database objects. You cannot:
Remove an asymmetric object from the device database
Query an asymmetric object from the device database
You can only create an asymmetric object, which then syncs unidirectionally to the Atlas database linked to your App with Device Sync.
For more information, see: Create an Asymmetric Object.
In C++, define an asymmetric object the same way you would
a regular C++ struct or class. Provide a REALM_ASYMMETRIC_SCHEMA
with the
struct or class name as the first argument. Add the names of any properties
that you want the database to persist.
An asymmetric_object
broadly has the same supported types as realm::object
, with a few exceptions:
Asymmetric objects can link to the following types: -
object
-embedded_object
-std::vector<embedded_object>
In C#, to define a asymmetric object, inherit from the the
IAsymmetricObject
interface and declare the class a partial
class.
In Dart, to define an asymmetric object, create a class model and add the
RealmModel
annotation. Pass ObjectType.asymmetricObject
to the @RealmModel()
annotation.
Follow the Define an SDK Object Model procedure detailed on this
page to generate the RealmObject
model and schema definitions.
Then, use the generated RealmObject
model in your application code.
The Java SDK does not support Data Ingest or asymmetric objects. Use the Kotlin SDK for heavy insert-only workloads.
In JavaScript, to define an asymmetric object, set the asymmetric
property
on your object schema.
In the Kotlin SDK, to define an asymmetric object type, create a Kotlin class that implements the AsymmetricRealmObject interface:
The Java SDK does not support Data Ingest or asymmetric objects. Use the Kotlin SDK for heavy insert-only workloads.
In Objective-C, to define an embedded object, create a class that inherits from RLMAsymmetricObject.
RLMAsymmetricObject
broadly supports the same property types as
RLMObject
, with a few exceptions:
- Asymmetric objects can only link to embedded objects
RLMObject
andRLMArray<RLMObject>
properties are not supported in Swift SDK versions 10.42.3 and earlier. In Swift SDK versions 10.42.4 and later, asymmetric objects can link to non-embedded objects.RLMEmbeddedObject
andRLMArray<RLMEmbeddedObject>
are supported.
You cannot link to an RLMAsymmetricObject
from within an RLMObject
.
Doing so throws an error.
In Swift, to define an asymmetric object, create a class that inherits from AsymmetricObject.
AsymmetricObject
broadly supports the same property types as Object
,
with a few exceptions:
- Asymmetric objects can only link to embedded objects
Object
andList<Object>
properties are not supported in Swift SDK versions 10.42.3 and earlier. In Swift SDK versions 10.42.4 and later, asymmetric objects can link to non-embedded objects.EmbeddedObject
andList<EmbeddedObject>
are supported.
You cannot link to an AsymmetricObject
from within an Object
. Doing so
throws an error.
In TypeScript, to define an asymmetric object, set the asymmetric
property
on your object schema.
struct WeatherSensorReading { realm::primary_key<realm::object_id> _id{realm::object_id::generate()}; std::string deviceId; double temperatureInFahrenheit; int64_t windSpeedInMph; }; REALM_ASYMMETRIC_SCHEMA(WeatherSensorReading, _id, deviceId, temperatureInFahrenheit, windSpeedInMph)
// The documentation does not currently have this code example in C#. // Please refer to the other languages or related pages for example code.
(ObjectType.asymmetricObject)class _WeatherSensor { () "_id") ( late ObjectId id; late String deviceId; late double modtemperatureInFahrenheitel; late double barometricPressureInHg; late double windSpeedInMph; }
// The Java SDK does not support this API.
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', }, }; }
// Implements the `AsymmetricRealmObject` interface class WeatherSensor : AsymmetricRealmObject { var id: ObjectId = ObjectId() var deviceId: String = "" var temperatureInFarenheit: Float = 0.0F var barometricPressureInHg: Float = 0.0F var windSpeedInMph: Int = 0 }
// The Java SDK does not support this API.
// The documentation does not currently have this code example in Objective-C. // Please refer to the other languages or related pages for example code.
class WeatherSensor: AsymmetricObject { true) var _id: ObjectId (primaryKey: var deviceId: String var temperatureInFahrenheit: Float var barometricPressureInHg: Float var windSpeedInMph: Int }
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', }, }; }
Define a Geospatial Object
To persist GeoPoint
data, it must conform to the
GeoJSON spec.
The C++ SDK does not currently support geospatial data.
In C#, to create a class that conforms to the GeoJSON spec:
Create an embedded object (a class that inherits from IEmbeddedObject).
At a minimum, add the two fields required by the GeoJSON spec:
A field of type
IList<double>
that maps to a "coordinates" (case sensitive) property in the object schema.A field of type
string
that maps to a "type" property. The value of this field must be "Point".
The following example shows an embedded class named "CustomGeoPoint" that is used to persist GeoPoint data:
public partial class CustomGeoPoint : IEmbeddedObject { [ ] public IList<double> Coordinates { get; } = null!; [ ] private string Type { get; set; } = "Point"; public CustomGeoPoint(double latitude, double longitude) { Coordinates.Add(longitude); Coordinates.Add(latitude); } }
Use the Embedded Class
You then use the custom GeoPoint class in your SDK object model, as shown in the following example.
In Dart, to create a class that conforms to the GeoJSON spec, you:
Create an embedded object. For more information about embedded objects, refer to Define an SDK Object Model.
At a minimum, add the two fields required by the GeoJSON spec:
A field of type
double[]
that maps to a "coordinates" (case sensitive) property in the schema.A field of type
string
that maps to a "type" property. The value of this field must be "Point".
The following example shows an embedded class named MyGeoPoint
that is
used to persist geospatial data:
// To store geospatial data, create an embedded object with this structure. // Name it whatever is most convenient for your application. (ObjectType.embeddedObject)class _MyGeoPoint { // These two properties are required to persist geo data. final String type = 'Point'; final List<double> coordinates = const []; // You can optionally implement convenience methods to simplify // creating and working with geospatial data. double get lon => coordinates[0]; set lon(double value) => coordinates[0] = value; double get lat => coordinates[1]; set lat(double value) => coordinates[1] = value; GeoPoint toGeoPoint() => GeoPoint(lon: lon, lat: lat); }
Use the Embedded Class
You then use the custom MyGeoPoint
class in your data model, as shown
in the following example:
The Java SDK does not support geospatial data. Use the Kotlin SDK to work with GeoJSON and location data.
In JavaScript, to create a class that conforms to the GeoJSON spec, you:
Create an embedded SDK object. For more information about embedded objects, refer to Define an Embedded Object.
At a minimum, add the two fields required by the GeoJSON spec:
A field of type
double[]
that maps to a "coordinates" (case sensitive) property in the object schema.A field of type
string
that maps to a "type" property. The value of this field must be "Point".
To simplify geodata persistance, you can define a model that implements
CanonicalGeoPoint
, which already has the correct shape. The following
example shows an embedded class named MyGeoPoint
that is used
to persist geospatial data:
class MyGeoPoint { type = "Point"; constructor(long, lat) { this.coordinates = [long, lat]; } static schema = { name: "MyGeoPoint", embedded: true, properties: { type: "string", coordinates: "double[]", }, }; }
Use the Embedded Class
You then use the custom MyGeoPoint
class in your SDK model, as shown in the
following example:
class Company extends Realm.Object { static schema = { name: "Company", properties: { _id: "int", location: "MyGeoPoint", }, primaryKey: "_id", }; }
You add instances of your class to the database just like any other SDK
model. However, in this example, because the MyGeoPoint
class does not
extend Realm.Object
, we must specify MyGeoPoint.schema
when opening
the database:
In the Kotlin SDK, to create a class that conforms to the GeoJSON spec, you:
Create an embedded object (a class that inherits from EmbeddedRealmObject).
At a minimum, add the two fields required by the GeoJSON spec:
A field of type
String
property that maps to atype
property with the value of"Point"
:var type: String = "Point"
A field of type
RealmList<Double>
that maps to acoordinates
property in the object schema containing a latitude/longitude pair:var coordinates: RealmList<Double> = realmListOf()
The following example shows an embedded class named CustomGeoPoint
that is used
to persist geospatial data:
class CustomGeoPoint : EmbeddedRealmObject { constructor(latitude: Double, longitude: Double) { coordinates.apply { add(longitude) add(latitude) } } // Empty constructor required by Realm constructor() : this(0.0, 0.0) // Name and type required by Realm var coordinates: RealmList<Double> = realmListOf() // Name, type, and value required by Realm private var type: String = "Point" var latitude: Double get() = coordinates[1] set(value) { coordinates[1] = value } var longitude: Double get() = coordinates[0] set(value) { coordinates[0] = value } }
Use the Embedded Class
Use the customGeoPoint
class in your SDK model, as shown in the
following example:
The Java SDK does not support geospatial data. Use the Kotlin SDK to work with GeoJSON and location data.
The SDK does not have an example of persisting GeoJSON data with Objective-C. Refer to the Swift language for details about persisting geospatial data with the Swift SDK.
To persist geospatial data with the Swift SDK, create a GeoJSON-compatible embedded class that you can use in your data model.
Your custom embedded object must contain the two fields required by the GeoJSON spec:
A field of type
String
property that maps to atype
property with the value of"Point"
:@Persisted var type: String = "Point"
A field of type
List<Double>
that maps to acoordinates
property containing a latitude/longitude pair:@Persisted private var coordinates: List<Double>
In TypeScript, to create a class that conforms to the GeoJSON spec, you:
Create an embedded SDK object. For more information about embedded objects, refer to Define an Embedded Object.
At a minimum, add the two fields required by the GeoJSON spec:
A field of type
double[]
that maps to a "coordinates" (case sensitive) property in the object schema.A field of type
string
that maps to a "type" property. The value of this field must be "Point".
To simplify geodata persistance, you can define a model that implements
CanonicalGeoPoint
, which already has the correct shape. The following
example shows an embedded class named MyGeoPoint
that is used
to persist geospatial data:
// Implement `CanonicalGeoPoint` // for convenience when persisting geodata. class MyGeoPoint implements CanonicalGeoPoint { coordinates!: GeoPosition; type = "Point" as const; constructor(long: number, lat: number) { this.coordinates = [long, lat]; } static schema: ObjectSchema = { name: "MyGeoPoint", embedded: true, properties: { type: "string", coordinates: "double[]", }, }; }
Use the Embedded Class
You then use the custom MyGeoPoint
class in your SDK model, as shown in the
following example:
class Company extends Realm.Object<Company> { _id!: number; location!: MyGeoPoint; static schema: ObjectSchema = { name: "Company", properties: { _id: "int", location: "MyGeoPoint", }, primaryKey: "_id", }; }
You add instances of your class to the database just like any other SDK
model. However, in this example, because the MyGeoPoint
class does not
extend Realm.Object
, we must specify MyGeoPoint.schema
when opening
the database:
// The C++ SDK does not currently support this API.
public partial class Company : IRealmObject { [ ] [ ] public Guid Id { get; private set; } = Guid.NewGuid(); public CustomGeoPoint? Location { get; set; } public Company() { } }
// Use the GeoJSON-compatible class as a property in your model. ()class _Company { () late ObjectId id; _MyGeoPoint? location; }
// The Java SDK does not support this API.
const realm = await Realm.open({ // `MyGeoPoint` does not extend `Realm.Object`, so you pass // only the `.schema` when opening the realm. schema: [Company, MyGeoPoint.schema], }); // Add geospatial object to realm. realm.write(() => { realm.create(Company, { _id: 6, location: new MyGeoPoint(-122.35, 47.68), }); realm.create(Company, { _id: 9, location: new MyGeoPoint(-121.85, 47.9), }); });
class Company : RealmObject { var _id: ObjectId = ObjectId() var location: CustomGeoPoint? = null }
// The Java SDK does not support this API.
// The documentation does not currently have this code example in Objective-C. // Please refer to the other languages or related pages for example code.
class CustomGeoPoint: EmbeddedObject { private var type: String = "Point" private var coordinates: List<Double> public var latitude: Double { return coordinates[1] } public var longitude: Double { return coordinates[0] } convenience init(_ latitude: Double, _ longitude: Double) { self.init() // Longitude comes first in the coordinates array of a GeoJson document coordinates.append(objectsIn: [longitude, latitude]) } }
const realm = await Realm.open({ // `MyGeoPoint` does not extend `Realm.Object`, so you pass // only the `.schema` when opening the realm. schema: [Company, MyGeoPoint.schema], }); // Add geospatial object to realm. realm.write(() => { realm.create(Company, { _id: 6, location: new MyGeoPoint(-122.35, 47.68), }); realm.create(Company, { _id: 9, location: new MyGeoPoint(-121.85, 47.9), }); });
Important
Cannot Persist Geospatial Data Types
Currently, you can only persist geospatial data. Geospatial data types
cannot be persisted directly. For example, you can't declare a property
that is of type GeoBox
.
These types can only be used as arguments for geospatial queries.
Define Property Behaviors
You can define property types that have special behavior. These property types provide additional functionality or constraints to these fields in your data model.
Index a Property
When you add an index to a property, the SDK can perform equality matches and range-based query operations on the property much more efficiently. Without indexes, the SDK scans every object of its type to select the objects that match the given query. However, if an applicable index exists for a query, the SDK uses the index to limit the number of objects it must inspect.
Indexes are special data structures that store a small portion of a database's data in an easy-to-traverse form. The index stores the value of a specific field ordered by the value of the field.
When indexing a property, keep in mind:
Indexes can be nullable.
Primary keys are indexed by default.
You cannot combine standard indexes with full-text search (FTS) indexes on the same property. To create an FTS index on a property, refer to the Enable Full-Text Search on a Property section on this page.
Indexing a property makes some types of queries more efficient, but can slow down writes and increase the size of the database file:
Indexes support more efficient match and range-based query operations.
Indexes make insert and update operation speed slightly slower.
Adding an index to a property increases disk space consumed by your database file. Each index entry is a minimum of 12 bytes.
Indexes on the client and on the server are entirely separate. The only effect that adding indexes has on initial Sync performance is to make it slightly slower as the index has to be populated.
Generally, you should only add an index when you need to improve the performance of a specific equality-based query, and the minor slowdown in writes is acceptable with your app's write patterns.
The C++ SDK does not currently support indexing a property.
You can index properties of these data types:
bool
byte
short
int
long
DateTimeOffset
char
string
ObjectId
UUID
To index a property, use the Indexed
attribute. With the Indexed
attribute, you can specify the type of index
on the property by using the IndexType
enum.
In the following example, we have a default ("General") index on the Name
property:
You can index properties of these data types:
bool
int
String
ObjectId
Uuid
DateTime
RealmValue
To create an index on the field, add the Indexed annotation to the property.
You can index properties of these data types:
String
UUID
ObjectId
Integer
orint
Long
orlong
Short
orshort
Byte
orbyte[]
Boolean
orbool
Date
RealmAny
To index a field, use the @Index annotation.
You can index properties of these data types:
string
integer
boolean
Date
UUID
ObjectId
To define an index for a given property, set indexed
to true
.
The following Car
object schema defines an index on the _id
property.
You can index properties of these data types:
String
Byte
Short
Int
Long
Boolean
RealmInstant
ObjectId
RealmUUID
To create an index on a property, use the @Index annotation on the property.
You can index properties of these data types:
String
UUID
ObjectId
Integer
orint
Long
orlong
Short
orshort
Byte
orbyte[]
Boolean
orbool
Date
RealmAny
To index a field, use the @Index annotation.
You can index proeprties of these data types:
string
integer
boolean
NSDate
To index a property, override +[RLMObject indexedProperties] and return a list of indexed property names.
You can index properties of these data types:
string
integer
boolean
Date
UUID
ObjectId
AnyRealmValue
To index a property, declare the property with
indexed:true
on the @Persisted
notation.
You can index properties of these data types:
string
integer
boolean
Date
UUID
ObjectId
To define an index for a given property, set indexed
to true
.
The following Car
object schema defines an index on the _id
property.
// The C++ SDK does not currently support this API.
public partial class Person : IRealmObject { [ ] public string Name { get; set; } [ ] public string Biography { get; set; } }
class _Vehicle { () late ObjectId id; late String? maybeDescription; // optional value late double milesTravelled = 0; // 0 is default value () late String notInRealmModel; () late String make; 'wheels') // 'wheels' is property name in the RealmObject ( late int numberOfWheels; }
import io.realm.RealmObject; import io.realm.annotations.Index; public class Frog extends RealmObject { private String name; private int age; private String species; private String owner; public Frog(String name, int age, String species, String owner) { this.name = name; this.age = age; this.species = species; this.owner = owner; } public Frog(){} // RealmObject subclasses must provide an empty constructor public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSpecies() { return species; } public void setSpecies(String species) { this.species = species; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } }
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", }; }
var name: String = "" // Indexed property
import io.realm.RealmObject import io.realm.annotations.Index open class Frog : RealmObject { var name: String? = null var age = 0 var species : String? = null var owner: String? = null constructor(name: String?, age: Int, species: String?, owner: String?) { this.name = name this.age = age this.species = species this.owner = owner } constructor() {} // RealmObject subclasses must provide an empty constructor }
@interface Book : RLMObject @property int priceCents; @property NSString *title; @end @implementation Book // Return a list of indexed property names + (NSArray *)indexedProperties { return @[@"title"]; } @end
class Book: Object { var priceCents = 0 true) var title = "" (indexed: }
// The documentation does not currently have this code example in TypeScript. // Please refer to the other languages or related pages for example code.
Note
When you create an index with the SDK, you are creating it in the device persistence layer and not on an Atlas collection. If you need to query an Atlas collection directly and want to improve performance, refer to Create, View, Drop, and Hide Indexes.
Enable Full-Text Search on a Property
The SDK supports Full-Text Search (FTS) on string properties. You do this by adding a FTS index on the property. When you query a FTS property, the FTS index enables searching for multiple words and phrases and excluding others.
Similar to a regular index, FTS indexes have performance benefits and implications. Adding a FTS index to a property makes some types of queries more efficient, but can slow down writes and increase the size of the database file:
FTS indexes support more efficient match and range-based query operations when seraching for multiple words or phrases and excluding others.
FTS indexes make insert and update operation speed slightly slower.
Adding a FTS index to a property increases disk space consumed by your database file. Each index entry is a minimum of 12 bytes.
The C++ SDK does not currently support Full-Text Search.
To index an FTS property, use the Indexed
attribute with the IndexType.FullText
enum. In the following example, we have a FullText
index on the
Biography
property:
To create an FTS index on a property, use the @Indexed
annotation and specify the RealmIndexType
as fullText
. This enables full-text queries on the property. In the
following example, we mark the pattern and material properties with the FTS annotation:
The Java SDK does not support Full-Text Search. If you would like to use FTS, use the Kotlin SDK, instead.
To create an FTS index, set the indexed
type to 'full-text'
. This enables full-text queries on the property. In the
following example, we set the indexed type for the name
property to 'full-text'
.
To create an FTS index on a property, use the @FullText annotation.
The Java SDK does not support Full-Text Search. If you would like to use FTS, use the Kotlin SDK, instead.
The Swift SDK does not currently support Full-Text Search.
The Swift SDK does not currently support Full-Text Search.
To create an FTS index, set the indexed
type to 'full-text'
. This enables full-text queries on the property. In the
following example, we set the indexed type for the name
property to 'full-text'
.
// The C++ SDK does not currently support this API.
public partial class Person : IRealmObject { [ ] public string Name { get; set; } [ ] public string Biography { get; set; } }
()class _Rug { () late ObjectId id; (RealmIndexType.fullText) late String pattern; (RealmIndexType.fullText) late String material; late int softness; }
// The Java SDK does not support this API.
// The documentation does not currently have this code example in JavaScript. // Please refer to the other languages or related pages for example code.
var physicalDescription: String? = null // Full-text search indexed property
// The Java SDK does not support this API.
// The Swift SDK does not currently support this API.
// The Swift SDK does not currently support this API.
class Book extends Realm.Object<Book> { name!: string; price?: number; static schema: ObjectSchema = { name: "Book", properties: { name: { type: "string", indexed: "full-text" }, price: "int?", }, }; }
You cannot combine standard indexes with full-text search (FTS) indexes on the same property. To create a standard index on a property, refer to the Index a Property section on this page.
Note
Character Limitations for Full-Text Search Indexes
For Full-Text Search (FTS) indexes, only ASCII and Latin-1 alphanumerical chars (most western languages) are included in the index.
Indexes are diacritics- and case-insensitive.
Designate a Primary Key
A primary key is a property that uniquely identifies an object.
Primary keys allow you to efficiently find, update, and upsert objects.
Primary keys are subject to the following limitations:
You can define only one primary key per object model.
Primary key values must be unique across all instances of an object in the database. The SDK throws an error if you try to insert a duplicate primary key value.
Primary key values are immutable. To change the primary key value of an object, you must delete the original object and insert a new object with a different primary key value.
Embedded objects cannot define a primary key.
If you are using Device Sync, your models must
have a primary key named _id
.
C++ supports primary keys of the following types, and their optional variants:
int64_t
realm::object_id
realm::uuid
std::string
Additionally, a required realm::enum
property can be a primary key, but
realm::enum
cannot be optional if it is used as a primary key.
Set a property as a primary key with the primary_key
template.
You can create a primary key with any of the following types (or their nullable counterparts):
ObjectId
UUID
string
char
byte
short
int
long
To designate a property as the object's primary key, use the Primary Key attribute.
You can create a primary key with any of the following types (or their nullable counterparts):
String
int
ObjectId
Uuid
To designate a property as the object's primary key, use the PrimaryKey annotation.
You can create a primary key with any of the following types:
String
UUID
ObjectId
Integer
orint
Long
orlong
Short
orshort
Byte
orbyte[]
To designate a property as the primary key for the object, annotate the property with the @PrimaryKey annotation.
To specify a property as an object type's primary key, set the schema's
primaryKey
field to the property name.
The following Car
object schema specifies the _id
property as its
primary key.
You can create a primary key with any of the following types:
String
Byte
Char
Short
Int
Long
ObjectId
RealmUUID
To specify a property as the object type's primary key, use the @PrimaryKey annotation.
You can create a primary key with any of the following types:
String
UUID
ObjectId
Integer
orint
Long
orlong
Short
orshort
Byte
orbyte[]
To designate a property as the primary key for the object, annotate the property with the @PrimaryKey annotation.
You can create a primary key with any of the following types:
RLMPropertyTypeString
RLMPropertyTypeInt
To designate a property as an object's primary key, override +[RLMObject primaryKey].
You can create a primary key with any of the following types:
String
Int
ObjectId
UUID
To designate a property as an object's primary key, declare the property with
primaryKey: true
on the @Persisted
notation.
To specify a property as an object type's primary key, set the schema's
primaryKey
field to the property name.
The following Car
object schema specifies the _id
property as its
primary key.
struct Person { realm::primary_key<int64_t> _id; std::string name; int64_t age; // Create relationships by pointing an Object field to another struct or class Dog *dog; }; REALM_SCHEMA(Person, _id, name, age, dog)
public partial class Dog : IRealmObject { [ ] public string Name { get; set; } public int Age { get; set; } public Person? Owner { get; set; } }
class _Vehicle { () late ObjectId id; late String? maybeDescription; // optional value late double milesTravelled = 0; // 0 is default value () late String notInRealmModel; () late String make; 'wheels') // 'wheels' is property name in the RealmObject ( late int numberOfWheels; }
import io.realm.RealmObject; import io.realm.annotations.PrimaryKey; public class Frog extends RealmObject { private String name; private int age; private String species; private String owner; public Frog(String name, int age, String species, String owner) { this.name = name; this.age = age; this.species = species; this.owner = owner; } public Frog(){} // RealmObject subclasses must provide an empty constructor public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSpecies() { return species; } public void setSpecies(String species) { this.species = species; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } }
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", }; }
var _id: ObjectId = ObjectId() // Primary key property
import io.realm.RealmObject import io.realm.annotations.PrimaryKey open class Frog : RealmObject { var name : String? = null var age = 0 var species: String? = null var owner: String? = null constructor(name: String?, age: Int, species: String?, owner: String?) { this.name = name this.age = age this.species = species this.owner = owner } constructor() {} // RealmObject subclasses must provide an empty constructor }
@interface Project : RLMObject @property NSInteger id; // Intended primary key @property NSString *name; @end @implementation Project // Return the name of the primary key property + (NSString *)primaryKey { return @"id"; } @end
class Project: Object { true) var id = 0 (primaryKey: var name = "" }
// The documentation does not currently have this code example in TypeScript. // Please refer to the other languages or related pages for example code.
Define an Optional Property
The SDK supports defining optional properties. The SDK uses language-specific idioms for handling optional model properties. The SDK considers all model properties required unless you designate them as optional, or ignore them.
In C++, define an optional type using the class template std::optional.
In C#, value types, such as int
and bool
, are implicitly non-nullable.
However, they can be made optional by using the question mark (?
) notation.
Beginning with C# 8.0, nullable reference types were introduced. If your project
is using C# 8.0 or later, you can also declare reference types, such as string
and byte[]
, as nullable with ?
.
Note
Beginning with .NET 6.0, the nullable context is enabled by default for new projects. For older projects, you can manually enable it. For more information, refer to https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-reference-types#setting-the-nullable-context.
The SDK fully supports the nullable-aware context and uses nullability to determine whether a property is required or optional.
Alternatives to the Nullable-Aware Context
If you are using the older schema type definition (your classes derive from
the RealmObject
base class), or you do not have nullability enabled, you
must use the [Required]
attribute for any required string
and byte[]
property.
You may prefer to have more flexibility in defining the nullability of properties
in your SDK objects. You can do so by setting realm.ignore_objects_nullability = true
in a global configuration file.
If you enable realm.ignore_objects_nullability
, the SDK ignores nullability
annotations on object properties, including collections of SDK objects.
In Dart, value types are implicitly non-nullable, but can be made optional
(nullable) by appending ?. Include ?
to make properties optional.
Fields marked with Java object types are nullable by default. All other types (primitives) are required by default. You can mark a nullable field with the @Required annotation to prevent that field from holding a null value.
The following types are nullable:
String
Date
UUID
ObjectId
Integer
Long
Short
Byte
orbyte[]
Boolean
Float
Double
Primitive types like int
and long
are non-nullable by
default and cannot be made nullable, as they cannot be set to a
null value.
To mark a property as optional, append a question mark ?
to its type.
The following Car
schema defines an optional miles
property of type int
.
SDK object properties must be mutable and initialized when declared.
The Kotlin SDK does not currently support abstract properties. You
can declare properties optional (nullable) using the built-in
?
Kotlin operator, or you can assign a default value to a property
when you declare it.
In Kotlin, fields are considered nullable only if a field is marked nullable with the Kotlin ? operator except for the following types:
String
Date
UUID
ObjectId
Decimal128
RealmAny
You can require any type that ends with the Kotlin ?
operator, such as Int?
.
The RealmList
type is non-nullable by default and cannot be
made nullable.
In Objective-C, pointer-type properties are considered optional in the data model unless you specifically declare a property as required. To declare a given property as required, implement the requiredProperties method and return an array of required property names.
Implicitly required properties, such as properties of primitive types, do
not need to be manually included in the requiredProperties
array.
You can declare properties as optional or required (non-optional) using standard Swift syntax.
To mark a property as optional, append a question mark ?
to its type.
std::optional<std::string> optStringName;
public partial class Person : IRealmObject { /* Reference Types */ public string NonNullableName { get; set; } public string? NullableName { get; set; } public byte[] NonNullableArray { get; set; } public byte[]? NullableArray { get; set; } /* Value Types */ public int NonNullableInt { get; set; } public int? NullableInt { get; set; } /* Realm Objects */ public Dog? NullableDog { get; set; } // public Dog NonNullableDog { get; set; } // Compile-time error /* Collections of Primitives */ public IList<int> IntListWithNonNullableValues { get; } public IList<int?> IntListWithNullableValues { get; } // public IList<int>? NullableListOfInts { get; } // Compile-time error /* Collections of Realm Objects */ public IList<Dog> ListOfNonNullableObjects { get; } // public IList<Dog>? NullableListOfObjects { get; } // Compile-time error // public IList<Dog?> ListOfNullableObjects { get; } // Compile-time error public ISet<Dog> SetOfNonNullableObjects { get; } // public ISet<Dog>? NullableSetOfObjects { get; } // Compile-time error // public ISet<Dog?> SetOfNullableObjects { get; } // Compile-time error public IDictionary<string, Dog?> DictionaryOfNullableObjects { get; } // public IDictionary<string, Dog> DictionaryOfNonNullableObjects { get; } // Compile-time error // public IDictionary<string, Dog>? NullableDictionaryOfObjects { get; } // Compile-time error [ ] public IQueryable<Dog> MyDogs { get; } // [Backlink(nameof(Dog.People))] // public IQueryable<Dog?> MyDogs { get; } // Compile-time error }
class _Vehicle { () late ObjectId id; late String? maybeDescription; // optional value late double milesTravelled = 0; // 0 is default value () late String notInRealmModel; () late String make; 'wheels') // 'wheels' is property name in the RealmObject ( late int numberOfWheels; }
// The documentation does not have this code example in Java. // Please refer to the other languages or related pages for example code.
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", }; }
var stringOpt: String? = null
// The documentation does not have this code example in Kotlin for the Java SDK. // Please refer to the other languages or related pages for example code.
@interface Person : RLMObject // Required property - included in `requiredProperties` // return value array @property NSString *name; // Optional string property - not included in `requiredProperties` @property NSString *address; // Required numeric property @property int ageYears; // Optional numeric properties use NSNumber tagged // with RLMInt, RLMFloat, etc. @property NSNumber<RLMFloat> *heightCm; @end @implementation Person // Specify required pointer-type properties here. // Implicitly required properties (such as properties // of primitive types) do not need to be named here. + (NSArray<NSString *> *)requiredProperties { return @[@"name"]; } @end
class Person: Object { // Required string property var name = "" // Optional string property var address: String? // Required numeric property var ageYears = 0 // Optional numeric property var heightCm: Float? }
// The documentation does not currently have this code example in TypeScript. // Please refer to the other languages or related pages for example code.
Special Rules
The SDK has some special rules about when things must be nullable, and when they cannot be nullable:
You must declare properties that are SDK object types as nullable.
You cannot declare collections (list, sets, backlinks, and dictionaries) as nullable, but their parameters may be nullable according to the following rules:
For all types of collections, if the parameters are primitives (value- or reference-types), they can be required or nullable.
For lists, sets, and backlinks, if the parameters are SDK objects, they cannot be nullable.
For dictionaries with a value type of an SDK object, you must declare the value type parameter as nullable.
Ignore a Property
You can ignore a property to avoid persisting that property's value.
An ignored property behaves exactly like a managed property, except:
They aren't stored to the database
They can't be used in queries
They don't trigger notifications
You can mix managed and ignored properties within a model.
To ignore a property, omit it from the object schema.
A property is ignored by default if it is not autoimplemented or does not have a setter.
Ignore an object property with the Ignored attribute.
To ignore a property, add the Ignored
annotation to the property in your RealmModel
. When you
generate the model, the object generator doesn't
include the property in the RealmObject
schema or persist it to the
database.
Ignore a field from an SDK object model with the @Ignore annotation.
Note
The SDK ignores static and transient Fields
Fields marked static
or transient
are always ignored, and do
not need the @Ignore
annotation.
To ignore a property, omit it from the object schema.
To ignore a property and prevent it from persisting to the database, use the @Ignore annotation.
Ignore a field from an SDK object model with the @Ignore annotation.
Note
The SDK ignores static and transient Fields
Fields marked static
or transient
are always ignored, and do
not need the @Ignore
annotation.
To ignore a property, override +[RLMObject ignoredProperties] and return a list of ignored property names.
To ignore a property, omit the @Persisted
notation from the property
attribute.
To ignore a property, omit it from the object schema.
namespace realm { struct Employee { realm::primary_key<int64_t> _id; std::string firstName; std::string lastName; // You can use this property as you would any other member // Omitting it from the schema means the SDK ignores it std::string jobTitle_notPersisted; }; // The REALM_SCHEMA omits the `jobTitle_notPersisted` property // The SDK does not store and cannot retrieve a value for this property REALM_SCHEMA(Employee, _id, firstName, lastName) } // namespace realm
// Rather than store an Image in Realm, // store the path to the Image... public string ThumbnailPath { get; set; } // ...and the Image itself can be // in-memory when the app is running: [ ]public Image? Thumbnail { get; set; }
class _Vehicle { () late ObjectId id; late String? maybeDescription; // optional value late double milesTravelled = 0; // 0 is default value () late String notInRealmModel; () late String make; 'wheels') // 'wheels' is property name in the RealmObject ( late int numberOfWheels; }
import io.realm.RealmObject; import io.realm.annotations.Ignore; public class Frog extends RealmObject { private String name; private int age; private String species; // can you ever really own a frog persistently? private String owner; public Frog(String name, int age, String species, String owner) { this.name = name; this.age = age; this.species = species; this.owner = owner; } public Frog(){} // RealmObject subclasses must provide an empty constructor public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSpecies() { return species; } public void setSpecies(String species) { this.species = species; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } }
// The documentation does not currently have this code example in JavaScript. // Please refer to the other languages or related pages for example code.
var age: Int = 0 // Ignored property
import io.realm.RealmObject import io.realm.annotations.Ignore open class Frog : RealmObject { var name: String? = null var age = 0 var species: String? = null // can you ever really own a frog persistently? var owner : String? = null constructor(name: String?, age: Int, species: String?, owner: String?) { this.name = name this.age = age this.species = species this.owner = owner } constructor() {} // RealmObject subclasses must provide an empty constructor }
@interface Person : RLMObject @property NSInteger tmpId; @property (readonly) NSString *name; // read-only properties are automatically ignored @property NSString *firstName; @property NSString *lastName; @end @implementation Person + (NSArray *)ignoredProperties { return @[@"tmpId"]; } - (NSString *)name { return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName]; } @end
class Person: Object { // If some properties are marked as @Persisted, // any properties that do not have the @Persisted // annotation are automatically ignored. var tmpId = 0 // The @Persisted properties are managed var firstName = "" var lastName = "" // Read-only properties are automatically ignored var name: String { return "\(firstName) \(lastName)" } // If you mix the pre-10.10 property declaration // syntax `@objc dynamic` with the 10.10+ @Persisted // annotation within a class, `@objc dynamic` // properties are ignored. @objc dynamic var email = "" }
// The documentation does not currently have this code example in TypeScript. // Please refer to the other languages or related pages for example code.
Set a Default Value for a Property
You can specify a default value for a property in your data model.
You cannot set a default value on a collection, except to set it to null or nil. Even if you set a collection to nil, collections are always initialized on first access, so will never be nil.
You can use the built-in language features to assign a default value to a property. In C#, you can assign a default value on primitives in the property declaration.
Note
Default Values and Nullability
While default values ensure that a newly created object cannot contain
a value of null
(unless you specify a default value of null
),
they do not impact the nullability of a property. For details about
nullability, refer to Define an Optional Property.
You can use the built-in language features to assign a default value to a property. Assign a default value in the property declaration.
To assign a default value to a field, use the built-in language features. Use the class constructor(s) to assign default values.
Note
Default Values and Nullability
While default values ensure that a newly created object cannot contain
a value of null
(unless you specify a default value of null
),
they do not impact the nullability of a field. For details about
nullability, refer to Define an Optional Property.
To define a default value, set the value of the property to an object with a
type
field and a default
field.
The following Car
object schema specifies a default value of 0
for
the miles
property.
To assign a default value to a field, use the built-in language features. Assign default values in the field declaration.
Note
Default Values and Nullability
While default values ensure that a newly created object cannot contain
a value of null
(unless you specify a default value of null
),
they do not impact the nullability of a field. For details about
nullability, refer to Define an Optional Property.
To define a default value, set the value of the property to an object with a
type
field and a default
field.
// The documentation does not currently have this code example in C++. // Please refer to the other languages or related pages for example code.
public partial class Person : IRealmObject { public string Name { get; set; } = "foo"; public IList<PhoneNumber> PhoneNumbers { get; } = null!; }
class _Vehicle { () late ObjectId id; late String? maybeDescription; // optional value late double milesTravelled = 0; // 0 is default value () late String notInRealmModel; () late String make; 'wheels') // 'wheels' is property name in the RealmObject ( late int numberOfWheels; }
import io.realm.RealmObject; public class Frog extends RealmObject { private String name = "Kitty"; private int age; private String species; private String owner; public Frog(String name, int age, String species, String owner) { this.name = name; this.age = age; this.species = species; this.owner = owner; } public Frog(){} // RealmObject subclasses must provide an empty constructor public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSpecies() { return species; } public void setSpecies(String species) { this.species = species; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } }
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", }; }
// The documentation does not currently have this code example in Kotlin. // Please refer to the other languages or related pages for example code.
import io.realm.RealmObject open class Frog : RealmObject { var name = "Kitty" var age = 0 var species: String? = null var owner: String? = null constructor(name: String, age: Int, species: String?, owner: String?) { this.name = name this.age = age this.species = species this.owner = owner } constructor() {} // RealmObject subclasses must provide an empty constructor }
// The documentation does not currently have this code example in Objective-C. // Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in Swift. // Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in TypeScript. // Please refer to the other languages or related pages for example code.
Define Custom Setters
For some platforms and languages, the idiomatic developer experience involves defining custom setters. The SDK does not directly persist properties using custom setters. Instead, you can store the property value in a private property, and then map that value to a public property that uses the custom setter.
The SDK stores the private property, while you modify its value through the public property.
In the following code, the private email
property is stored in the database,
but the public Email
property, which provides validation, is not persisted.
// The documentation does not currently have this code example in C++. // Please refer to the other languages or related pages for example code.
// This property will be stored in the Realm private string email { get; set; } // Custom validation of the email property. // This property is *not* stored in Realm. public string Email { get { return email; } set { if (!value.Contains("@")) throw new Exception("Invalid email address"); email = value; } }
// The documentation does not currently have this code example in Dart. // Please refer to the other languages or related pages for example code.
// The documentation does not have this code example in Java. // Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in JavaScript. // Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in Kotlin. // Please refer to the other languages or related pages for example code.
// The documentation does not have this code example in Kotlin for the Java SDK. // Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in Objective-C. // Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in Swift. // Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in TypeScript. // Please refer to the other languages or related pages for example code.
Model Unstructured Data
Unstructured data is data that doesn't easily conform to an expected schema, making it difficult or impractical to model to individual data classes. For example, your app might have highly variable data or dynamic data whose structure is unknown at runtime.
The SDK provides the ability to store collections of mixed data within a mixed property. You can use this feature to model complex data structures, such as JSON or MongoDB documents, without having to define a strict data model.
You can work with these collections the same way you would a non-mixed collection:
You can nest mixed collections up to 100 levels.
You can query on and react to changes on mixed collections.
You can find and update individual mixed collection elements.
However, storing data in mixed collections is less performant than using a structured schema or serializing JSON blobs into a single string property.
Tip
Use a map of mixed data types when the type is unknown but each value will have a unique identifier.
Use a list of mixed data types when the type is unknown but the order of objects is meaningful.
C++ does not currently support modeling unstructured data as a collection of the mixed property type.
Starting in SDK version 12.22.0, you can store collections of mixed data
within a RealmValue
property.
To model unstructured data in your app, define the appropriate properties in
your schema as RealmValue types. You can then
set these RealmValue
properties as a list
or a dictionary of RealmValue
elements.
Note that RealmValue
cannot represent a set or an embedded object.
New in version 2.0.0.
Starting in Flutter SDK version 2.0.0, you can store
collections of mixed data within a RealmValue
property.
To model unstructured data in your app, define the appropriate properties in
your schema as RealmValue types. You can then set
these RealmValue
properties as a RealmList
or a RealmMap collection of
RealmValue
elements.
Note that RealmValue
cannot represent a RealmSet
or an embedded object.
For example, you might use a RealmValue
that contains a map of mixed
data when modeling a variable event log object.
The Java SDK does not support modeling unstructured data as a collection of the mixed property type. If you would like to take advantage of more flexible data models, use the Kotlin SDK.
New in version 12.9.0.
Starting in Node.js SDK version 12.9.0, you can store
collections of mixed data within a mixed
property.
To model unstructured data in your app, define the appropriate properties in
your schema as mixed types. You can then set these
mixed
properties as a list or a
dictionary collection of mixed elements.
Note that mixed
cannot represent a set or an embedded object.
New in version 2.0.0.
Starting in Kotlin SDK version 2.0.0, you can store
collections of mixed data within a RealmAny
property.
To model unstructured data in your app, define the appropriate properties in
your schema as RealmAny types. You can then set
these RealmAny
properties as a list or a
dictionary collection of RealmAny
elements.
Note that RealmAny
cannot represent a RealmSet
or an embedded object.
The Java SDK does not support modeling unstructured data as a collection of the mixed property type. If you would like to take advantage of more flexible data models, use the Kotlin SDK.
New in version 10.51.0.
Starting in SDK version 10.51.0, you can store collections of mixed data
within an RLMValue
property.
To model unstructured data in your app, define the appropriate properties in
your schema as RLMValue types. You can then
set these RLMValue
properties as a list
or a dictionary collection of
RLMValue
elements.
Note that RLMValue
cannot represent a RLMSet
or an embedded
object.
New in version 10.51.0.
Starting in SDK version 10.51.0, you can store collections of mixed data
within a AnyRealmValue
property.
To model unstructured data in your app, define the appropriate properties in
your schema as AnyRealmValue types. You can then
set these AnyRealmValue
properties as a list
or a dictionary collection of
AnyRealmValue
elements.
Note that AnyRealmValue
cannot represent a MutableSet
or an embedded
object.
New in version 12.9.0.
Starting in Node.js SDK version 12.9.0, you can store
collections of mixed data within a mixed
property.
To model unstructured data in your app, define the appropriate properties in
your schema as mixed types. You can then set these
mixed
properties as a list or a
dictionary collection of mixed elements.
Note that mixed
cannot represent a set or an embedded object.
// The C++ SDK does not currently support this API.
// The documentation does not currently have this code example in C#. // Please refer to the other languages or related pages for example code.
// Define class with a `RealmValue` property ()class _EventLog { () late ObjectId id; late String eventType; late DateTime timestamp; late String userId; late RealmValue details; }
realm.write(() { // Add `eventLog` property data as a map of mixed data, which // also includes nested lists of mixed data realm.add(EventLog(ObjectId(), 'purchase', DateTime.now(), 'user123', details: RealmValue.from({ 'ipAddress': '192.168.1.1', 'items': [ {'id': 1, 'name': 'Laptop', 'price': 1200.00}, {'id': 2, 'name': 'Mouse', 'price': 49.99} ], 'total': 1249.99 }))); final eventLog = realm.all<EventLog>().first; final items = eventLog.details.asMap(); print(''' Event Type: ${eventLog.eventType} Timestamp: ${eventLog.timestamp} User ID: ${eventLog.userId} Details: Item: '''); for (var item in items.entries) { print('${item.key}: ${item.value}'); }
Event Type: purchase Timestamp: 2024-03-18 13:50:58.402979Z User ID: user123 Details: Item: ipAddress: RealmValue(192.168.1.1) items: RealmValue([RealmValue({id: RealmValue(1), name: RealmValue(Laptop), price: RealmValue(1200.0)}), RealmValue({id: RealmValue(2), name: RealmValue(Mouse), price: RealmValue(49.99)})]) total: RealmValue(1249.99)
// The Java SDK does not support this API.
// The documentation does not currently have this code example in JavaScript. // Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in Kotlin. // Please refer to the other languages or related pages for example code.
// The Java SDK does not support this API.
// The documentation does not currently have this code example in Objective-C. // Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in Swift. // Please refer to the other languages or related pages for example code.
// The documentation does not currently have this code example in TypeScript. // Please refer to the other languages or related pages for example code.
Map a Model or Property to a Different Name
Some of the SDK implementations provide the ability to map an SDK object model or property to a different stored name in the database. This can be useful when:
You work across platforms where naming conventions differ. For example, if your Device Sync schema property names use snake case, while your project uses camel case.
You want to change a class or field name without forcing a migration.
You need to support multiple model classes with the same name in different packages.
You want to use a class name that is longer than the 57-character limit enforced by the SDK.
If you're using Atlas Device Sync, the name that you specify when you map the model or property to a new name is the name used in the persisted App Services Schema.
Note
Migrations must use the persisted class or property name. Any schema errors reported also use the persisted name.
C++ does not currently provide an API to map a model or property name to a different stored name.
Use the [MapTo] attribute to rename a class or property.
Use the MapTo annotation to map an SDK object model or property to a different stored name.
Map a Model Name
Use the @RealmClass annotation to rename a class.
import io.realm.RealmObject; import io.realm.annotations.RealmClass; import io.realm.annotations.RealmNamingPolicy; public class Frog extends RealmObject { private String name; private int age; private String species; private String owner; public Frog(String name, int age, String species, String owner) { this.name = name; this.age = age; this.species = species; this.owner = owner; } public Frog(){} // RealmObject subclasses must provide an empty constructor public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSpecies() { return species; } public void setSpecies(String species) { this.species = species; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } }
Map a Property Name
Use the @RealmField annotation to rename a field:
import io.realm.RealmObject; import io.realm.annotations.RealmField; public class Frog extends RealmObject { private String name; private int age; private String species; private String owner; public Frog(String name, int age, String species, String owner) { this.name = name; this.age = age; this.species = species; this.owner = owner; } public Frog(){} // RealmObject subclasses must provide an empty constructor public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSpecies() { return species; } public void setSpecies(String species) { this.species = species; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } }
Assign a Naming Policy at the Module or Class Level
Alternatively, you can also assign a naming policy at the module or class levels to change the way that the SDK interprets field names.
You can define a naming policy at the module level, which affects all classes included in the module.
Map a Model Name
To use a different class name in your code than is stored in the database:
Set the
name
property of your SDK object's schema to the name that you want to use to store the object.Use the class name in the database configuration's
schema
property when you open the database.Use the mapped name for performing CRUD operations or when defining Sync Subscriptions.
In the following example, the SDK stores objects created with the
Task
class as 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`);
Map a Property Name
To use a different property name in your code than is stored in the database,
set mapTo
to the name of the property as it appears in your code.
In the following Car
object schema, the database stores the car's
model name with the snake case model_name
property. The schema maps the property
to modelName
for objects used in client code.
To map a Kotlin class or property name in your code to a different in the database:
Use the @PersistedName annotation on the Kotlin class or property.
Specify a class or property
name
that you want persisted to the database.
Map a Model Name
In this example, Frog
is the Kotlin class name used in the code
throughout the project to perform CRUD operations, and Frog_Entity
is the
persisted name to used to store objects in the database:
// Remapped class name class Frog : RealmObject { var _id: ObjectId = ObjectId() var name: String = "" var age: Int = 0 var species: String? = null var owner: String? = null }
Important
Querying by Remapped Class Names
When querying an inverse relationship on an object with a
remapped class name, you must use the persisted class name.
In the example above, you must query Frog_Entity
instead of
Frog
.
For more information, refer to Query Inverse Relationships.
Map a Property Name
In this example, species
is the Kotlin property name used in the code
throughout the project to perform CRUD operations and latin_name
is the
persisted name used to store values in the database:
Tip
Querying by Remapped Property Names
You can query by either the Kotlin name used in the code or by the persisted name stored in the database.
Map a Model Name
Use the @RealmClass annotation to rename a class.
import io.realm.RealmObject import io.realm.annotations.RealmClass import io.realm.annotations.RealmNamingPolicy open class Frog : RealmObject { var name: String? = null var age = 0 var species: String? = null var owner: String? = null constructor(name: String?, age: Int, species: String?, owner: String?) { this.name = name this.age = age this.species = species this.owner = owner } constructor() {} // RealmObject subclasses must provide an empty constructor }
Map a Property Name
Use the @RealmField annotation to rename a field.
import io.realm.RealmObject import io.realm.annotations.RealmField open class Frog : RealmObject { var name: String? = null var age = 0 var species: String? = null var owner: String? = null constructor(name: String?, age: Int, species: String?, owner: String?) { this.name = name this.age = age this.species = species this.owner = owner } constructor() {} // RealmObject subclasses must provide an empty constructor }
Assign a Naming Policy at the Module or Class Level
Alternatively, you can also assign a naming policy at the module or class levels to change the way that the SDK interprets field names.
You can define a naming policy at the module level, which affects all classes included in the module.
Map a Model Name
The Swift SDK does not support mapping a model name to a different name.
Map a Property Name
The documentation does not currently have an example of how to map a property name to a different persisted name with Objective-C.
Map a Model Name
The Swift SDK does not support mapping a model name to a different name.
Map a Property Name
Declare the name you want to use in your project as the @Persisted
property on the object model. Then, pass a dictionary containing the
public and private values for the property names via the
propertiesMapping()
function.
In this example, firstName
is the public property name we use in the code
throughout the project to perform CRUD operations. Using the propertiesMapping()
function, we map that to store values using the private property name
first_name
in the database. If we write to a synced database, the Sync
schema sees the values stored using the private property name first_name
.
Map a Model Name
To use a different class name in your code than is stored in the database:
Set the
name
property of your SDK object's schema to the name that you want to use to store the object.Use the class name in the database configuration's
schema
property when you open the database.Use the mapped name for performing CRUD operations or when defining Sync Subscriptions.
In the following example, the SDK stores objects created with the
Task
class as 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`);
Map a Property Name
To use a different property name in your code than is stored in the database,
set mapTo
to the name of the property as it appears in your code.
// The C++ SDK does not currently support this API.
[ ]public partial class Person : IRealmObject { public string Name { get; set; } }
public partial class Person : IRealmObject { [ ] public string Name { get; set; } }
()'naval_ship') (class _Boat { () late ObjectId id; late String name; late int? maxKnots; late int? nauticalMiles; }
class _Vehicle { () late ObjectId id; late String? maybeDescription; // optional value late double milesTravelled = 0; // 0 is default value () late String notInRealmModel; () late String make; 'wheels') // 'wheels' is property name in the RealmObject ( late int numberOfWheels; }
import io.realm.annotations.RealmModule; import io.realm.annotations.RealmNamingPolicy; public class MyModule { }
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", }; }
var species: String? = null // Remapped property
import io.realm.annotations.RealmModule import io.realm.annotations.RealmNamingPolicy open class MyModule
// The documentation does not currently have this code example in Objective-C. // Please refer to the other languages or related pages for example code.
class Person: Object { var firstName = "" var lastName = "" override class public func propertiesMapping() -> [String: String] { ["firstName": "first_name", "lastName": "last_name"] } }
// The documentation does not currently have this code example in TypeScript. // Please refer to the other languages or related pages for example code.
Transform Model Data for View Models
You can define a projection of your model objects and properties to transform the data into different shapes and structures. You might want to use a projection to make data available in a specific form, but persist it in a different form.
For example, you might want to work with persisted data in a different way in a view model or based on certain business logic. This simplifies using and testing SDK objects in your application.
With projection, you can use a subset of your object's properties directly in the UI, or transform them. When you use a projection for this, you get all the benefits of the SDK's live objects:
The class-projected object live updates
You can observe it for changes
You can apply changes directly to the properties in write transactions
Projection is currently only available in the Swift SDK.
Transform Persisted Properties
When you define a projection, you can transform the original persisted property in several ways:
Passthrough: the property is the same name and type as the original object
Rename: the property has the same type as the original object, but a different name
Keypath resolution: use keypath resolution to access properties of the original object, including embedded object properties
Collection mapping: Project lists or sets of
Object
s orEmbeddedObject
s as a collection of primitive valuesExclusion: when you use a model projection, the underlying object's properties that are not projected through the model projection are excluded. This enables you to watch for changes to a model projection and not see changes for properties that are not part of the model projection.
Define a Projection
Projection is not currently supported for this programming language. If you'd like to file a feature request for this functionality, refer to Get Help.
Projection is not currently supported for this programming language. If you'd like to file a feature request for this functionality, refer to Get Help.
Projection is not currently supported for this programming language. If you'd like to file a feature request for this functionality, refer to Get Help.
Projection is not currently supported for this programming language. If you'd like to file a feature request for this functionality, refer to Get Help.
Projection is not currently supported for this programming language. If you'd like to file a feature request for this functionality, refer to Get Help.
Projection is not currently supported for this programming language. If you'd like to file a feature request for this functionality, refer to Get Help.
Projection is not currently supported for this programming language. If you'd like to file a feature request for this functionality, refer to Get Help.
The documentation is currently missing an example of how to define a projection in Objective-C.
Define a class projection by creating a class of type Projection. Specify the Object
or EmbeddedObject base whose
properties you want to use in the class projection. Use the @Projected
property wrapper to declare a property that you want to project from a
@Persisted
property on the base object.
Note
When you use a List or a Set in a class projection, the type in the projection should be ProjectedCollection.
The examples in this section use a simple data set. The two SDK object
types are Person
and an embedded object Address
. A Person
has
a first and last name, an optional Address
, and a list of friends
consisting of other Person
objects. An Address
has a city and country.
See the model for these two classes, Person
and Address
, below:
class Person: Object { var firstName = "" var lastName = "" var address: Address? var friends = List<Person>() } class Address: EmbeddedObject { var city: String = "" var country = "" }
Projection is not currently supported for this programming language. If you'd like to file a feature request for this functionality, refer to Get Help.
// The C++ SDK does not currently support this API.
// The .NET SDK does not currently support this API.
// The Flutter SDK does not currently support this API.
// The Java SDK does not support this API.
// The Node.js SDK does not currently support this API.
// The Kotlin SDK does not currently support this API.
// The Java SDK does not support this API.
// The documentation does not currently have this code example in Objective-C. // Please refer to the other languages or related pages for example code.
class PersonProjection: Projection<Person> { Person.firstName) var firstName // Passthrough from original object (\ Person.address?.city) var homeCity // Rename and access embedded object property through keypath (\ Person.friends.projectTo.firstName) var firstFriendsName: ProjectedCollection<String> // Collection mapping (\}
// This API is not currently available in TypeScript.