Navigation

Realm Objects

MongoDB Realm applications model data as objects composed of property-value pairs that each contain one or more primitive data types or other Realm objects. Realm objects are essentially the same as regular objects, but they also include additional features like real-time updating data views and reactive change event handlers.

Every Realm object has an object type that refers to the object's class. Objects of the same type share an object schema that defines the properties and relationships of those objects. In most languages you define object schemas using the native class implementation.

Beaker IconExample

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.

public class Dog : RealmObject
{
[PrimaryKey]
[MapTo("_id")]
public ObjectId Id { get; set; }
[Required]
public string Name { get; set; }
public int Age { get; set; }
public string Breed { get; set; }
public IList<Person> Owners { get; }
}
public class Person : RealmObject
{
[PrimaryKey]
[MapTo("_id")]
public ObjectId Id { get; set; }
[Required]
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); */
}
Info With Circle IconCreated with Sketch.Note

To define a collection of objects within an object, use an IList<T> with only a getter. You do not need to initialize it in the constructor, as realm will generate a collection instance the first time the property is accessed.

Objects in Realm clients are live objects that update automatically to reflect data changes, including synced remote changes, and emit notification events that you can subscribe to whenever their underlying data changes. You can use live objects to work with object-oriented data natively without an ORM tool.

Live objects are direct proxies to the underlying stored data, which means that a live object doesn't directly contain data. Instead, a live object always references the most up-to-date data on disk and lazy loads property values when you access them from a collection. This means that a realm can contain many objects but only pay the performance cost for data that the application is actually using.

Valid write operations on a live object automatically persist to the realm and propagate to any other synced clients. You do not need to call an update method, modify the realm, or otherwise "push" updates.

An object schema is a configuration object that defines the properties and relationships of a Realm object. Realm client applications define object schemas with the native class implementation in their respective language using the Realm Object Model.

Object schemas specify constraints on object properties such as the data type of each property and whether or not a property is required. Schemas can also define relationships between object types in a realm.

Every Realm app has a Realm Schema composed of a list of object schemas for each type of object that the realms in that application may contain. MongoDB Realm guarantees that all objects in a realm conform to the schema for their object type and validates objects whenever they're created, modified, or deleted.

Realm Database supports the following property data types and their nullable counterparts:

  • bool
  • byte
  • short
  • int
  • long
  • float
  • double
  • decimal
  • char
  • string
  • byte[]
  • DateTimeOffset
  • Decimal128 from MongoDB.Bson
  • ObjectId from MongoDB.Bson
  • A RealmObject subclass
  • An EmbeddedObject subclass (see Embedded Objects)
  • IList<T> where T is any of the previous data types (see Lists)

The byte, char, short, int, and long types are all stored as 64 bit integer values within Realm Database.

If you choose to provide custom constructors, you must declare a public constructor with no arguments.

Realm objects can contain lists of all supported data types. You can model these collections by defining a getter-only property of type IList<T>, where T can be any data type (excluding lists).

Lists of objects cannot contain null values - i.e. deleting an object from the database will also remove it from any lists where it existed. Lists of primitive types can contain null values. If null values should not be allowed, do not use nullable types in the list declaration (i.e., use IList<double> instead of IList<double?>) or add the [Required] attribute if the list contains reference types, such as string or byte[].

Realm Database provides the ability to nest objects within other objects. This has several advantages:

  • If using Realm Sync, objects will translate into MongoDB documents that follow a denormalized data model.
  • When you delete an object that contains another object, the delete operation removes both objects from the realm, so unused objects don't accumulate in your realm file, taking up valuable space on user's mobile devices.

To embed an object, extend EmbeddedObject for the class that you'd like to nest within another class:

public class Address : EmbeddedObject
{
public ObjectId Id { get; set; }
public string Street { get; set; }
public string City { get; set; }
}
public class Contact : RealmObject
{
[PrimaryKey]
public ObjectId Id { get; set; }
public string Name { get; set; }
public Address Address { get; set; } // embed a single address
}

Then, any time you reference that class from another class, Realm Database will embed the referenced class within the enclosing class.

Bulb IconTip
See Also:

A primary key is a property that uniquely identifies an object. You can create a primary key with any of the following types (or their nullable counterparts):

  • ObjectId
  • string
  • char
  • byte
  • short
  • int
  • long

You may define a primary key on a single property for an object type as part of the object schema. Realm Database automatically indexes primary key properties, which allows you to efficiently read and modify objects based on their primary key.

If an object type has a primary key, then all objects of that type must include the primary key property with a value that is unique among objects of the same type in a realm.

Info With Circle IconCreated with Sketch.Note

Once you assign a property as a primary key, you cannot change it.

The following example demonstrates how to designate a primary key in an object schema:

public class Dog : RealmObject
{
[PrimaryKey]
public string Name { get; set; }
public int Age { get; set; }
public Person Owner { get; set; }
}

In C#, value types are implicitly non-nullable, but can be made optional by appending ?. Reference types, such as string and byte[], are implicitly nullable and can be made required by annotating them with the [Required] attribute. Properties of types that inherit from RealmObject or EmbeddedObject are special and can always be null. Applying [Required] on such a property will result in a compilation error.

You can use the [Required] attribute as seen in the following example:

public class Person : RealmObject
{
[Required]
public string Name { get; set; }
public IList<Dog> Dogs { get; }
}

You can use the built-in language features to assign a default value to a property. In C#, you can assign a default value in the property declaration.

public class Person : RealmObject
{
public string Name { get; set; } = "foo";
}
Info With Circle IconCreated with Sketch.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. To make a property non-nullable, see Required Properties.

Indexes support the efficient execution of queries in Realm Database. Without indexes, Realm Database must perform a collection scan, i.e. scan every document in a collection, to select those documents that match a query. If an appropriate index exists for a query, Realm Database can use the index to limit the number of documents that it must inspect.

Indexes are special data structures that store a small portion of a realm's data in an easy to traverse form. The index stores the value of a specific property ordered by the value of the property. The ordering of the index entries supports efficient equality matches and range-based query operations.

Adding an index to a property makes write operations slightly slower, but makes certain queries faster. Indexes require space in your realm file, so adding an index to a property will increase disk space consumed by your realm file.

You can index properties with the following types:

  • bool
  • byte
  • short
  • int
  • long
  • DateTimeOffset
  • char
  • string
  • ObjectId

To index a property, use the [Indexed] attribute:

public class Person : RealmObject
{
[Indexed]
public string Name { get; set; }
public IList<Dog> Dogs { get; }
}

Realm Database supports several kinds of object relationships.

Bulb IconTip
See Also:

To set up a many-to-one or one-to-one relationship, create a property in your application whose type inherits RealmObject or EmbeddedObject:

public class Dog : RealmObject
{
// ... other property declarations
public Person Owner { get; set; };
}
public class Person : RealmObject
{
public string Name { get; set; }
}

Each Dog references zero or one Person instances. Nothing prevents multiple Dog instances from referencing the same Person as an owner; the distinction between a many-to-one and a one-to-one relationship is up to your application.

Setting a relationship property to null removes the connection between objects, but Realm Database does not delete the referenced object unless that object is embedded.

You can create a relationship between one object and any number of objects using a property of type IList<T> in your application, where T is a subclass of RealmObject or EmbeddedObject:

public class Dog : RealmObject
{
public string Name { get; set; }
}
public class Person : RealmObject
{
// ... other property declarations
public IList<Dog> Dogs { get; }
}

By default, Realm Database relationships are unidirectional. You can follow a link from one class to a referenced class, but not in the opposite direction. You can provide a link in the opposite direction with the [Backlink] attribute:

class Dog : RealmObject
{
// To-one relationship from the Dog to its owner
public Person Owner { get; set; }
}
class Person : RealmObject
{
// An inverse relationship that returns all Dog instances that have Dog.Owner set to
// the current Person.
[Backlink(nameof(Dog.Owner))]
public IQueryable<Dog> Dogs { get; }
// To-many relationship, containing a collection of all hobbies the current person enjoys
public IList<Hobby> Hobbies { get; }
}
class Hobby : RealmObject
{
// An inverse relationship that returns all Person instances that have the current Hobby
// instance in their Hobbies list.
[Backlink(nameof(Person.Hobbies))]
public IQueryable<Person> PeopleWithThatHobby { get; }
}

Since relationships are many-to-one or many-to-many, following inverse relationships can result in zero, one, or many objects.

Like any other RealmResults set, you can query an inverse relationship.

If you don't want to save a property in your model to a realm, you can ignore that property. A property is ignored by default if it is not autoimplemented or does not have a setter.

Ignore a property from a Realm object model with the [Ignored] attribute:

[Ignored]
public Image Headshot { get; set; }

By default, Realm Database uses the name defined in the model class to represent properties internally. In some cases you might want to change this behavior:

  • To make it easier to work across platforms, since naming conventions differ.
  • To change a property name in .NET without forcing a migration.

Choosing an internal name that differs from the name used in model classes has the following implications:

  • Migrations must use the internal name when creating classes and properties.
  • Schema errors reported will use the internal name.

Use the [MapTo] attribute to rename a property:

public class Person : RealmObject
{
[MapTo("moniker")]
public string Name { get; set; }
}

By default, Realm Database uses the name defined in the model class to represent classes internally. In some cases you might want to change this behavior:

  • To support multiple model classes with the same simple name in different namespaces.
  • To make it easier to work across platforms, since naming conventions differ.
  • To use a class name that is longer than the 57 character limit enforced by Realm Database.
  • To change a class name in .NET without forcing a migration.

Use the [MapTo] attribute to rename a class:

[MapTo("Human")]
public class Person : RealmObject
{
public string Name { get; set; }
}

By default, your application's Realm Schema includes all classes that inherit from RealmObject or EmbeddedObject. If you only want to include a a subset of these classes in your Realm Schema, you can update your configuration to include the specific classes you want:

// Declare your schema
class LoneClass : RealmObject
{
public string Name { get; set;}
}
// In your main function, define your config
var config = new RealmConfiguration("RealmWithOneClass.realm");
config.ObjectClasses = new[] { typeof(LoneClass) };
// or specifying two classes in the Realm
config.ObjectClasses = new[] { typeof(Dog), typeof(Cat) };

Realm supports 128-bit decimal values with the Decimal128 Bson type. When defining a decimal type, you can use the Decimal128 Bson type or the .NET decimal type, even though it is only a 96-bit decimal. The SDK automatically converts between the two, although you risk losing precision or range. The following example shows how to use both the Decimal128 Bson type and the .NET decimal type:

public class MyClassWithDecimals {
[PrimaryKey]
public ObjectId _id { get; } = ObjectId.GenerateNewId();
// Standard (96-bit) decimal value type
public decimal VeryPreciseNumber { get; set; }
// 128-bit Decimal128
public Decimal128 EvenMorePreciseNumber { get; set; }
public Decimal128 AnotherEvenMorePreciseNumber { get; set; }
// Nullable decimal or Decimal128 are supported, too
public decimal? MaybeDecimal { get; set; }
public Decimal128? MaybeDecimal128 { get; set; }
public void PlayWithDecimals()
{
var myInstance = new MyClassWithDecimals();
// To store decimal values:
realm.Write(() =>
{
myInstance.VeryPreciseNumber = 1.234567890123456789M;
myInstance.EvenMorePreciseNumber = Decimal128.Parse("987654321.123456789");
// Decimal128 has explicit constructors that take a float or a double
myInstance.EvenMorePreciseNumber = new Decimal128(9.99999);
});
}
}
  • Realm objects are of a type defined as you would any other class.
  • Realm objects are live: they always reflect the latest version on disk and update automatically when the underlying object changes.
  • A Realm object type may have a primary key property to uniquely identify each instance of the object type.
  • The Realm object's schema defines the properties of the object and which properties are optional, which properties have a default value, and which properties are indexed.
Give Feedback