The examples on this page use the data model of a project
management app that has two Realm object types: Project
and Task
. A Project
has zero or more Tasks
.
See the schema for these two classes, Project
and
Task
, below:
import org.bson.types.ObjectId; |
|
import io.realm.RealmObject; |
import io.realm.annotations.PrimaryKey; |
import io.realm.annotations.RealmClass; |
import io.realm.annotations.Required; |
|
public class ProjectTask extends RealmObject { |
@PrimaryKey |
public ObjectId _id; |
@Required |
public String name; |
public String assignee; |
public int progressMinutes; |
public boolean isComplete; |
public int priority; |
@Required |
public String _partition; |
} |
import org.bson.types.ObjectId; |
|
import io.realm.RealmList; |
import io.realm.RealmObject; |
import io.realm.annotations.PrimaryKey; |
import io.realm.annotations.RealmClass; |
import io.realm.annotations.Required; |
|
public class Project extends RealmObject { |
@PrimaryKey |
public ObjectId _id; |
@Required |
public String name; |
public RealmList<ProjectTask> tasks = new RealmList<>(); |
} |
import io.realm.RealmObject |
import io.realm.annotations.PrimaryKey |
import io.realm.annotations.Required |
import org.bson.types.ObjectId |
|
open class ProjectTask( |
@PrimaryKey |
var _id: ObjectId = ObjectId(), |
@Required |
var name: String = "", |
var assignee: String? = null, |
var progressMinutes: Int = 0, |
var isComplete: Boolean = false, |
var priority: Int = 0, |
var _partition: String = "" |
): RealmObject() |
import io.realm.RealmList |
import io.realm.RealmObject |
import io.realm.annotations.PrimaryKey |
import io.realm.annotations.Required |
import org.bson.types.ObjectId |
|
open class Project( |
@PrimaryKey |
var _id: ObjectId = ObjectId(), |
@Required |
var name: String = "", |
var tasks: RealmList<ProjectTask> = RealmList(), |
): RealmObject() |
Within a transaction, you can update a Realm object the same
way you would update any other object in your language of
choice. Just assign a new value to the property or update
the property.
The following example changes the turtle's name to "Archibald" and
sets Archibald's age to 101 by assigning new values to properties:
realm.executeTransaction(r -> { |
|
Turtle turtle = r.where(Turtle.class).findFirst(); |
|
|
turtle.setName("Archibald"); |
turtle.setAge(101); |
}); |
realm.executeTransaction { r: Realm -> |
|
val turtle = r.where(Turtle::class.java).findFirst() |
|
|
turtle!!.name = "Archibald" |
turtle.age = 101 |
} |
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.
The following example demonstrates how to upsert an object with
realm. We create a new turtle enthusiast named "Drew" and then
update their name to "Andy" using insertOrUpdate():
realm.executeTransaction(r -> { |
ObjectId id = new ObjectId(); |
TurtleEnthusiast drew = new TurtleEnthusiast(); |
drew.set_id(id); |
drew.setName("Drew"); |
drew.setAge(25); |
|
|
r.insertOrUpdate(drew); |
TurtleEnthusiast andy = new TurtleEnthusiast(); |
andy.set_id(id); |
andy.setName("Andy"); |
andy.setAge(56); |
|
|
r.insertOrUpdate(andy); |
}); |
realm.executeTransaction { r: Realm -> |
val id = ObjectId() |
val drew = TurtleEnthusiast() |
drew._id = id |
drew.name = "Drew" |
drew.age = 25 |
|
|
r.insertOrUpdate(drew) |
val andy = TurtleEnthusiast() |
andy._id = id |
andy.name = "Andy" |
andy.age = 56 |
|
|
r.insertOrUpdate(andy) |
} |
You can also use copyToRealmOrUpdate() to
either create a new object based on a supplied object or update an
existing object with the same primary key value. Use the
CHECK_SAME_VALUES_BEFORE_SET
ImportFlag to only update fields
that are different in the supplied object:
The following example demonstrates how to insert an object or, if an object already
exists with the same primary key, update only those fields that differ:
realm.executeTransaction(r -> { |
ObjectId id = new ObjectId(); |
TurtleEnthusiast drew = new TurtleEnthusiast(); |
drew.set_id(id); |
drew.setName("Drew"); |
drew.setAge(25); |
|
|
r.insertOrUpdate(drew); |
TurtleEnthusiast andy = new TurtleEnthusiast(); |
andy.set_id(id); |
andy.setName("Andy"); |
|
|
|
r.copyToRealmOrUpdate(andy, ImportFlag.CHECK_SAME_VALUES_BEFORE_SET); |
}); |
realm.executeTransaction { r: Realm -> |
val id = ObjectId() |
val drew = TurtleEnthusiast() |
drew._id = id |
drew.name = "Drew" |
drew.age = 25 |
|
|
r.insertOrUpdate(drew) |
val andy = TurtleEnthusiast() |
andy._id = id |
andy.name = "Andy" |
|
|
r.copyToRealmOrUpdate(andy, |
ImportFlag.CHECK_SAME_VALUES_BEFORE_SET) |
} |
Realm supports collection-wide updates. A collection update
applies the same update to specific properties of several
objects in a collection at once.
The following example demonstrates how to update a
collection. Thanks to the implicit inverse
relationship between the Turtle's
owner
property and the TurtleEnthusiast's turtles
property,
Realm automatically updates Josephine's list of turtles
when you use setObject()
to update the "owner" property for all turtles in the collection.
realm.executeTransaction(r -> { |
|
TurtleEnthusiast josephine = r.createObject(TurtleEnthusiast.class, new ObjectId()); |
josephine.setName("Josephine"); |
|
|
RealmResults<Turtle> turtles = r.where(Turtle.class).equalTo("name", "Pierogi").findAll(); |
|
|
turtles.setObject("owner", josephine); |
}); |
realm.executeTransaction { r: Realm -> |
|
val josephine = realm.createObject( |
TurtleEnthusiast::class.java, |
ObjectId() |
) |
josephine.name = "Josephine" |
|
|
val turtles = r.where(Turtle::class.java) |
.equalTo("name", "Pierogi") |
.findAll() |
|
|
turtles.setObject("owner", josephine) |
} |
Because realm collections always reflect the latest state, they
can appear, disappear, or change while you iterate over a collection.
To get a stable collection you can iterate over, you can create a
snapshot of a collection's data. A snapshot guarantees the order of
elements will not change, even if an element is deleted or modified.
Iterator
objects created from RealmResults
use snapshots
automatically. Iterator
objects created from RealmList
instances do not use snapshots. Use
RealmList.createSnapshot()
or
RealmResults.createSnapshot()
to manually generate a snapshot you can iterate over manually:
The following example demonstrates how to iterate over a collection
safely using either an implicit snapshot created from a RealmResults
Iterator
or a manual snapshot created from a RealmList
:
RealmResults<Frog> frogs = realm.where(Frog.class) |
.equalTo("species", "bullfrog") |
.findAll(); |
|
|
realm.executeTransaction(r -> { |
for (Frog frog : frogs) { |
frog.setSpecies("Lithobates catesbeiana"); |
} |
}); |
|
|
realm.executeTransaction(r -> { |
OrderedRealmCollectionSnapshot<Frog> frogsSnapshot = frogs.createSnapshot(); |
for (int i = 0; i < frogsSnapshot.size(); i++) { |
frogsSnapshot.get(i).setSpecies("Lithobates catesbeiana"); |
} |
}); |
val frogs = realm.where(Frog::class.java) |
.equalTo("species", "bullfrog") |
.findAll() |
|
|
realm.executeTransaction { |
for (frog in frogs) { |
frog.species = "Lithobates catesbeiana" |
} |
} |
|
|
realm.executeTransaction { |
val frogsSnapshot = frogs.createSnapshot() |
for (i in frogsSnapshot.indices) { |
frogsSnapshot[i]!!.species = "Lithobates catesbeiana" |
} |
} |