Navigation

Writes

Overview

Realm Database uses a highly efficient storage engine to persist objects. You can create objects in a realm, update objects in a realm, and eventually delete objects from a realm. Because these operations modify the state of the realm, we call them writes.

Realm Database handles writes in terms of transactions. A transaction is a list of read and write operations that Realm Database treats as a single indivisible operation. In other words, a transaction is all or nothing: either all of the operations in the transaction succeed or none of the operations in the transaction take effect.

Remember

All writes must happen in a transaction.

A realm allows only one open transaction at a time. Realm Database blocks other writes on other threads until the open transaction is complete. Consequently, there is no race condition when reading values from the realm within a transaction.

When you are done with your transaction, Realm Database either commits it or cancels it:

  • When Realm Database commits a transaction, Realm Database writes all changes to disk. For synced realms, Realm Database queues the change for synchronization with MongoDB Realm.
  • When Realm Database cancels a write transaction or an operation in the transaction causes an error, all changes are discarded (or “rolled back”).

Realm is ACID Compliant

Realm Database guarantees that transactions are ACID compliant. This means that all committed write operations are guaranteed to be valid and that clients don’t see transient states in the event of a system crash.

Run a Transaction

Realm Database represents each transaction as a callback function that contains zero or more read and write operations. To run a transaction, define a transaction callback and pass it to the realm’s write method. Within this callback, you are free to create, read, update, and delete on the realm. If the code in the callback throws an exception when Realm Database runs it, Realm Database cancels the transaction. Otherwise, Realm Database commits the transaction immediately after the callback.

Concurrency Concerns

Since transactions block each other, it is best to avoid opening transactions on both the UI thread and a background thread. If you are using Sync, avoid opening transactions on the UI thread altogether, as Realm Database processes synchronizations on a background thread. If a background transaction blocks your UI thread’s transaction, your app may appear unresponsive.

Example

The following code shows how to run a transaction with the realm’s write method. If the code in the callback throws an exception, Realm Database cancels the transaction. Otherwise, Realm Database commits the transaction.

try! realm.write {
    // Create a person to take care of some dogs.
    let ali = Person(value: ["id": 1, "name": "Ali"])
    realm.add(ali)

    // Find dogs younger than 2.
    let puppies = realm.objects(Dog.self).filter("age < 2")
    
    // Give all puppies to Ali.
    puppies.setValue(ali, forKey: "owner")
}
[realm transactionWithBlock:^() {
    // Create a person to take care of some dogs.
    Person *ali = [[Person alloc] initWithValue:@{@"ID": @1, @"name": @"Ali"}];
    [realm addObject:ali];

    // Find dogs younger than 2.
    RLMResults<Dog *> *puppies = [Dog objectsInRealm:realm where:@"age < 2"];

    // Batch update: give all puppies to Ali.
    [puppies setValue:ali forKey:@"owner"];
}];

Create an Object

In general, instantiate Realm objects as you would any other object. In a transaction, you can add the object to the realm if the realm’s schema includes the object type. When you add an instance to the realm, it becomes managed by that realm.

With the Java and JavaScript SDKs, instead use the realm’s factory method in a transaction to instantiate your class. This automatically inserts the instance into the realm.

Example

This code demonstrates how to create an object with Realm Database:

// Instantiate the class. For convenience, you can initialize
// objects from dictionaries with appropriate keys and values.
let dog = Dog(value: ["name": "Max", "age": 5]);

// Open a thread-safe transaction.
try! realm.write {
    // Add the instance to the realm.
    realm.add(dog)
}
// Instantiate the class.
Dog *dog = [[Dog alloc] init];
dog.name = @"Max";
dog.age = 5;

// Open a thread-safe transaction.
[realm transactionWithBlock:^() {
    // Add the instance to the realm.
    [realm addObject:dog]; 
}];

Upsert an Object

An upsert is a write operation that either inserts a new object with a given primary key or updates an existing object that already has that primary key. We call this an upsert because it is an “update or insert” operation. This is useful when an object may or may not already exist, such as when bulk importing a dataset into an existing realm. Upserting is an elegant way to update existing entries while adding any new entries.

Example

This code demonstrates how to upsert an object with realm. We create a new user named “Drew” and then update their name to “Andy” via upsert:

try! realm.write {
    let drew = Person(value: ["id": 1234, "name": "Drew"]) 
    // Add a new person to the realm. Since nobody with ID 1234
    // has been added yet, this adds the instance to the realm.
    realm.add(drew, update: .modified)
    
    let andy = Person(value: ["id": 1234, "name": "Andy"]) 
    // Judging by the ID, it's the same person, just with a
    // different name. When `update` is:
    // - .modified: update the fields that have changed.
    // - .all: replace all of the fields regardless of
    //   whether they've changed.
    // - .error: throw an exception if a key with the same
    //   primary key already exists.
    realm.add(andy, update: .modified)
}
[realm transactionWithBlock:^() {
    Person *drew = [[Person alloc] initWithValue:@{@"ID": @1234, @"name": @"Drew"}];
    // Add a new person to the realm. Since nobody with ID 1234
    // has been added yet, this adds the instance to the realm.
    [realm addOrUpdateObject:drew];
    
    Person *andy = [[Person alloc] initWithValue:@{@"ID": @1234, @"name": @"Andy"}];
    // Judging by the ID, it's the same person, just with a different name.
    // This overwrites the original entry (i.e. Drew -> Andy).
    [realm addOrUpdateObject:andy];
}];

Update an Object

Within a transaction, you can update a Realm object the same way you would update any other object: just assign a new value to the property or update the property.

Example

This code changes the dog’s name to “Wolfie” and increments the age by 1:

// Open a thread-safe transaction.
try! realm.write {
    // Get a dog to update.
    let dog = realm.objects(Dog.self).first!;

    // Update some properties on the instance.
    // These changes are saved to the realm.
    dog.name = "Wolfie";
    dog.age += 1;
}
// Open a thread-safe transaction.
[realm transactionWithBlock:^() {
    // Get a dog to update.
    Dog *dog = [[Dog allObjectsInRealm: realm] firstObject];

    // Update some properties on the instance.
    // These changes are saved to the realm.
    dog.name = @"Wolfie";
    dog.age += 1;
}];

Update a Collection

Realm Database supports collection-wide updates. A collection update applies the same update to specific properties of several objects in a collection at once.

Example

The following code demonstrates how to update a collection. Thanks to the implicit inverse relationship between the Dog’s owner property and the Person’s dogs property, Realm Database automatically updates Ali’s list of dogs.

try! realm.write {
    // Create a person to take care of some dogs.
    let ali = Person(value: ["id": 1, "name": "Ali"])
    realm.add(ali)

    // Find dogs younger than 2.
    let puppies = realm.objects(Dog.self).filter("age < 2")
    
    // Give all puppies to Ali.
    puppies.setValue(ali, forKey: "owner")
}
[realm transactionWithBlock:^() {
    // Create a person to take care of some dogs.
    Person *ali = [[Person alloc] initWithValue:@{@"ID": @1, @"name": @"Ali"}];
    [realm addObject:ali];

    // Find dogs younger than 2.
    RLMResults<Dog *> *puppies = [Dog objectsInRealm:realm where:@"age < 2"];

    // Batch update: give all puppies to Ali.
    [puppies setValue:ali forKey:@"owner"];
}];

Delete an Object

To delete an object from a realm, pass the instance to the delete method of the realm within a transaction.

Do not use objects after delete

Realm Database throws an error if you try to use an object after it has been deleted.

Example

The following code shows how to delete one object from its realm:

try! realm.write {
    // Delete the instance from the realm.
    realm.delete(dog);

    // Discard the reference.
    dog = nil;
}
[realm transactionWithBlock:^() {
    // Delete the instance from the realm.
    [realm deleteObject:dog];

    // Discard the reference.
    dog = nil;
}];

Delete a Collection

To delete a collection of objects from a realm, pass the collection to the delete method of the realm within a transaction.

Example

The following code demonstrates how to delete a collection from a realm:

try! realm.write {
    // Find dogs younger than 2 years old.
    let puppies = realm.objects(Dog.self).filter("age < 2")

    // Delete the objects in the collection from the realm.
    realm.delete(puppies);
}
[realm transactionWithBlock:^() {
    // Find dogs younger than 2 years old.
    RLMResults<Dog *> *puppies = [Dog objectsInRealm:realm where:@"age < 2"];

    // Delete all objects in the collection from the realm.
    [realm deleteObjects:puppies];
}];

Cascading Delete

Sometimes, you have dependent objects that you want to delete when you delete the parent object. We call this a cascading delete. Realm Database will not delete the dependent objects for you. If you do not delete the objects yourself, they will remain orphaned in your realm. Whether or not this is a problem depends on your application’s needs.

Currently, the best way to delete dependent objects is to iterate through the dependencies and delete them before deleting the parent object.

Example

The following code demonstrates how to perform a cascading delete by first deleting all of Ali’s dogs, then deleting Ali:

try! realm.write {
    // Delete Ali's dogs.
    realm.delete(ali.dogs);
    // Delete Ali.
    realm.delete(ali);
}
[realm transactionWithBlock:^() {
    // Delete Ali's dogs.
    [realm deleteObjects:[ali dogs]];
    // Delete Ali.
    [realm deleteObject:ali];
}];

Delete All Instances of a Type

You can delete all instances of a Realm type from a realm as you would any collection.

Example

The following code demonstrates how to delete all Dog instances from a realm:

try! realm.write {
    // Delete all instances of Dog from the realm.
    let allDogs = realm.objects(Dog.self)
    realm.delete(allDogs);
}
[realm transactionWithBlock:^() {
    // Delete all instances of Dog from the realm.
    RLMResults<Dog *> *allDogs = [Dog allObjectsInRealm:realm];
    [realm deleteObjects:allDogs];
}];

Delete Everything

It is possible to delete all objects from the realm. This does not affect the schema of the realm. This is useful for quickly clearing out your realm while prototyping.

Example

The following code demonstrates how to delete everything from a realm:

try! realm.write {
    // Delete all objects from the realm.
    realm.deleteAll();
}
[realm transactionWithBlock:^() {
    // Delete all objects from the realm.
    [realm deleteAllObjects];
}];

Summary

  • Realm Database handles writes in terms of transactions. All writes must occur in a transaction.
  • Realm Database transactions are ACID compliant.
  • To write to Realm Database, define the transaction in a callback function that you pass to the realm’s write method.
←   Migrations Reads  →