Docs Menu
Docs Home
/ /
Atlas Device SDKs
/

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

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.

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.

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 or volatile 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 use RealmObject 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 annotation

  • the static keyword

  • the 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 the realm.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 or volatile 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 use RealmObject 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 annotation

  • the static keyword

  • the 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.

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 and Results 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.

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 and Results with a mixture of parent and subclass

Tip

Check out the code samples for working around these limitations.

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:

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 the realm.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.

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.

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
{
[PrimaryKey]
[MapTo("_id")]
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
{
[PrimaryKey]
[MapTo("_id")]
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

  1. 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.dart
    part 'modelFile.realm.dart';
  2. 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 public RealmObject 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 the RealmObject from the RealmModel, 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
    @RealmModel()
    class _Car {
    @PrimaryKey()
    late ObjectId id;
    late String make;
    late String? model;
    late int? miles;
    }
  3. 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
  4. 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 the RealmModel in step 2, access the RealmObject by importing the file with the RealmModel.

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;
@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
@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() }
};
myapp.dart
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
@PrimaryKey
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 {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var name = ""
@Persisted var breed: String?
@Persisted 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.

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.

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
{
[PrimaryKey]
[MapTo("_id")]
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
{
[PrimaryKey]
[MapTo("_id")]
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);
*/
}
@RealmModel()
class _Car {
@PrimaryKey()
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;
@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
@PrimaryKey
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
@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 {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var name = ""
@Persisted var breed: String?
@Persisted 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?',
},
};
}

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;
@RealmClass(embedded=true)
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
@RealmClass(embedded = true)
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
{
[MapTo("street")]
public string Street { get; set; }
[MapTo("city")]
public string City { get; set; }
[MapTo("country")]
public string Country { get; set; }
[MapTo("postalCode")]
public string PostalCode { get; set; }
}
public partial class Contact : IRealmObject
{
[PrimaryKey]
[MapTo("_id")]
public ObjectId Id { get; set; } = ObjectId.GenerateNewId();
[MapTo("_partition")]
public string Partition { get; set; }
[MapTo("name")]
public string Name { get; set; }
[MapTo("address")]
public Address? Address { get; set; } // embed a single address
}
public partial class Business : IRealmObject
{
[PrimaryKey]
[MapTo("_id")]
public ObjectId Id { get; set; } = ObjectId.GenerateNewId();
[MapTo("_partition")]
public string Partition { get; set; }
[MapTo("name")]
public string Name { get; set; }
[MapTo("addresses")]
public IList<Address> Addresses { get; }
}
// The generated `Address` class is an embedded object.
@RealmModel(ObjectType.embeddedObject)
class _Address {
late String street;
late String city;
late String state;
late String country;
}
@RealmModel()
class _Person {
@PrimaryKey()
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 {
@Persisted(primaryKey: true) var id = 0
@Persisted var name = ""
// To-many relationship - a person can have many dogs
@Persisted var dogs: List<Dog>
// Inverse relationship - a person can be a member of many clubs
@Persisted(originProperty: "members") var clubs: LinkingObjects<DogClub>
// Embed a single object.
// Embedded object properties must be marked optional.
@Persisted var address: Address?
convenience init(name: String, address: Address) {
self.init()
self.name = name
self.address = address
}
}
class DogClub: Object {
@Persisted var name = ""
@Persisted var members: List<Person>
// DogClub has an array of regional office addresses.
// These are embedded objects.
@Persisted var regionalOfficeAddresses: List<Address>
convenience init(name: String, addresses: [Address]) {
self.init()
self.name = name
self.regionalOfficeAddresses.append(objectsIn: addresses)
}
}
class Address: EmbeddedObject {
@Persisted var street: String?
@Persisted var city: String?
@Persisted var country: String?
@Persisted 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.

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 and RLMArray<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 and RLMArray<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 and List<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 and List<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.
@RealmModel(ObjectType.asymmetricObject)
class _WeatherSensor {
@PrimaryKey()
@MapTo("_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 {
@PersistedName("_id")
@PrimaryKey
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 {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var deviceId: String
@Persisted var temperatureInFahrenheit: Float
@Persisted var barometricPressureInHg: Float
@Persisted 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',
},
};
}

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:

  1. Create an embedded object (a class that inherits from IEmbeddedObject).

  2. 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
{
[MapTo("coordinates")]
public IList<double> Coordinates { get; } = null!;
[MapTo("type")]
private string Type { get; set; } = "Point";
public CustomGeoPoint(double latitude, double longitude)
{
Coordinates.Add(longitude);
Coordinates.Add(latitude);
}
}

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:

  1. Create an embedded object. For more information about embedded objects, refer to Define an SDK Object Model.

  2. 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.
@RealmModel(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);
}

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:

  1. Create an embedded SDK object. For more information about embedded objects, refer to Define an Embedded Object.

  2. 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[]",
},
};
}

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:

  1. Create an embedded object (a class that inherits from EmbeddedRealmObject).

  2. At a minimum, add the two fields required by the GeoJSON spec:

    • A field of type String property that maps to a type property with the value of "Point": var type: String = "Point"

    • A field of type RealmList<Double> that maps to a coordinates 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"
@Ignore
var latitude: Double
get() = coordinates[1]
set(value) {
coordinates[1] = value
}
@Ignore
var longitude: Double
get() = coordinates[0]
set(value) {
coordinates[0] = value
}
}

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 a type property with the value of "Point": @Persisted var type: String = "Point"

  • A field of type List<Double> that maps to a coordinates 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:

  1. Create an embedded SDK object. For more information about embedded objects, refer to Define an Embedded Object.

  2. 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[]",
},
};
}

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
{
[PrimaryKey]
[MapTo("_id")]
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.
@RealmModel()
class _Company {
@PrimaryKey()
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 {
@PrimaryKey
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 {
@Persisted private var type: String = "Point"
@Persisted 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.

You can define property types that have special behavior. These property types provide additional functionality or constraints to these fields in your data model.

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 or int

  • Long or long

  • Short or short

  • Byte or byte[]

  • Boolean or bool

  • 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 or int

  • Long or long

  • Short or short

  • Byte or byte[]

  • Boolean or bool

  • 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
{
[Indexed(IndexType.General)]
public string Name { get; set; }
[Indexed(IndexType.FullText)]
public string Biography { get; set; }
}
class _Vehicle {
@PrimaryKey()
late ObjectId id;
late String? maybeDescription; // optional value
late double milesTravelled = 0; // 0 is default value
@Ignored()
late String notInRealmModel;
@Indexed()
late String make;
@MapTo('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;
@Index 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",
};
}
@Index
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
@Index 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 {
@Persisted var priceCents = 0
@Persisted(indexed: true) var title = ""
}
// 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.

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
{
[Indexed(IndexType.General)]
public string Name { get; set; }
[Indexed(IndexType.FullText)]
public string Biography { get; set; }
}
@RealmModel()
class _Rug {
@PrimaryKey()
late ObjectId id;
@Indexed(RealmIndexType.fullText)
late String pattern;
@Indexed(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.
@FullText
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.

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 or int

  • Long or long

  • Short or short

  • Byte or byte[]

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 or int

  • Long or long

  • Short or short

  • Byte or byte[]

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
{
[PrimaryKey]
public string Name { get; set; }
public int Age { get; set; }
public Person? Owner { get; set; }
}
class _Vehicle {
@PrimaryKey()
late ObjectId id;
late String? maybeDescription; // optional value
late double milesTravelled = 0; // 0 is default value
@Ignored()
late String notInRealmModel;
@Indexed()
late String make;
@MapTo('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 {
@PrimaryKey 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",
};
}
@PrimaryKey
var _id: ObjectId = ObjectId() // Primary key property
import io.realm.RealmObject
import io.realm.annotations.PrimaryKey
open class Frog : RealmObject {
@PrimaryKey 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 {
@Persisted(primaryKey: true) var id = 0
@Persisted 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.

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.

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 or byte[]

  • 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;
#nullable enable
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
[Backlink(nameof(Dog.Person))]
public IQueryable<Dog> MyDogs { get; }
// [Backlink(nameof(Dog.People))]
// public IQueryable<Dog?> MyDogs { get; } // Compile-time error
}
class _Vehicle {
@PrimaryKey()
late ObjectId id;
late String? maybeDescription; // optional value
late double milesTravelled = 0; // 0 is default value
@Ignored()
late String notInRealmModel;
@Indexed()
late String make;
@MapTo('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
@Persisted var name = ""
// Optional string property
@Persisted var address: String?
// Required numeric property
@Persisted var ageYears = 0
// Optional numeric property
@Persisted 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.

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.

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:
[Ignored]
public Image? Thumbnail { get; set; }
class _Vehicle {
@PrimaryKey()
late ObjectId id;
late String? maybeDescription; // optional value
late double milesTravelled = 0; // 0 is default value
@Ignored()
late String notInRealmModel;
@Indexed()
late String make;
@MapTo('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?
@Ignore 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.
@Ignore
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?
@Ignore 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
@Persisted var firstName = ""
@Persisted 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.

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 {
@PrimaryKey()
late ObjectId id;
late String? maybeDescription; // optional value
late double milesTravelled = 0; // 0 is default value
@Ignored()
late String notInRealmModel;
@Indexed()
late String make;
@MapTo('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.

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.

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.
Data model
// Define class with a `RealmValue` property
@RealmModel()
class _EventLog {
@PrimaryKey()
late ObjectId id;
late String eventType;
late DateTime timestamp;
late String userId;
late RealmValue details;
}
Create unstructured data
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.

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;
@RealmClass(fieldNamingPolicy = RealmNamingPolicy.PASCAL_CASE)
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;
@RealmField("latinName") 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:

  1. Set the name property of your SDK object's schema to the name that you want to use to store the object.

  2. Use the class name in the database configuration's schema property when you open the database.

  3. 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:

  1. Use the @PersistedName annotation on the Kotlin class or property.

  2. 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:

@PersistedName(name = "Frog_Entity") // Remapped class name
class Frog : RealmObject {
@PrimaryKey
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
@RealmClass(fieldNamingPolicy = RealmNamingPolicy.PASCAL_CASE)
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
@RealmField("latinName") 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:

  1. Set the name property of your SDK object's schema to the name that you want to use to store the object.

  2. Use the class name in the database configuration's schema property when you open the database.

  3. 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.
Map a model name
[MapTo("Human")]
public partial class Person : IRealmObject
{
public string Name { get; set; }
}
Map a property name
public partial class Person : IRealmObject
{
[MapTo("moniker")]
public string Name { get; set; }
}
Map a model name
@RealmModel()
@MapTo('naval_ship')
class _Boat {
@PrimaryKey()
late ObjectId id;
late String name;
late int? maxKnots;
late int? nauticalMiles;
}
Map a property name
class _Vehicle {
@PrimaryKey()
late ObjectId id;
late String? maybeDescription; // optional value
late double milesTravelled = 0; // 0 is default value
@Ignored()
late String notInRealmModel;
@Indexed()
late String make;
@MapTo('wheels') // 'wheels' is property name in the RealmObject
late int numberOfWheels;
}
import io.realm.annotations.RealmModule;
import io.realm.annotations.RealmNamingPolicy;
@RealmModule(
allClasses = true,
classNamingPolicy = RealmNamingPolicy.LOWER_CASE_WITH_UNDERSCORES,
fieldNamingPolicy = RealmNamingPolicy.LOWER_CASE_WITH_UNDERSCORES
)
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",
};
}
@PersistedName("latin_name")
var species: String? = null // Remapped property
import io.realm.annotations.RealmModule
import io.realm.annotations.RealmNamingPolicy
@RealmModule(
allClasses = true,
classNamingPolicy = RealmNamingPolicy.LOWER_CASE_WITH_UNDERSCORES,
fieldNamingPolicy = RealmNamingPolicy.LOWER_CASE_WITH_UNDERSCORES
)
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 {
@Persisted var firstName = ""
@Persisted 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.

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.

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 or EmbeddedObject s as a collection of primitive values

  • Exclusion: 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.

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 {
@Persisted var firstName = ""
@Persisted var lastName = ""
@Persisted var address: Address?
@Persisted var friends = List<Person>()
}
class Address: EmbeddedObject {
@Persisted var city: String = ""
@Persisted 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> {
@Projected(\Person.firstName) var firstName // Passthrough from original object
@Projected(\Person.address?.city) var homeCity // Rename and access embedded object property through keypath
@Projected(\Person.friends.projectTo.firstName) var firstFriendsName: ProjectedCollection<String> // Collection mapping
}
// This API is not currently available in TypeScript.

Back

Model Data

Next

Define Property Types