Read & Write Data - iOS SDK¶
About These Examples¶
The examples on this page use the following models:
class DogToy: Object { @objc dynamic var name = "" } class Dog: Object { @objc dynamic var name = "" @objc dynamic var age = 0 @objc dynamic var color = "" @objc dynamic var currentCity = "" // To-one relationship @objc dynamic var favoriteToy: DogToy? } class Person: Object { @objc dynamic var id = 0 @objc dynamic var name = "" // To-many relationship - a person can have many dogs let dogs = List<Dog>() // Inverse relationship - a person can be a member of many clubs let clubs = LinkingObjects(fromType: DogClub.self, property: "members") override static func primaryKey() -> String? { return "id" } } class DogClub: Object { @objc dynamic var name = "" let members = List<Person>() }
Read Operations¶
Find a Specific Object by Primary Key¶
If you know the primary key for a given object, you can look it up directly with Realm.object(ofType:forPrimaryKey:).
let realm = try! Realm() let specificPerson = realm.object(ofType: Person.self, forPrimaryKey: 12345)
Query All Objects of a Given Type¶
To query for objects of a given type in a realm, pass the metatype
instance YourClassName.self
to Realm.objects(_:).
This returns a Results object
representing all objects of the given type in the realm.
let realm = try! Realm() // Access all dogs in the realm let dogs = realm.objects(Dog.self)
Filter Queries Based on Object Properties¶
A filter selects a subset of results based on the value(s) of one or more object properties. Realm Database provides a full-featured query engine that you can use to define filters.
To filter, call Results.filter(_:) with a query predicate.
let realm = try! Realm() // Access all dogs in the realm let dogs = realm.objects(Dog.self) // Filter by age let puppies = dogs.filter("age < 2") // Filter by person let dogsWithoutFavoriteToy = dogs.filter("favoriteToy == nil") // Filter by person's name let dogsWhoLikeTennisBalls = dogs.filter("favoriteToy.name == 'Tennis ball'")
To filter a query based on a property of an embedded object or a related object, use dot-notation as if it were in a regular, nested object.
Filter on Object ID Properties¶
The types in your predicate must match the types of the properties. Avoid comparing ObjectId properties to strings, as Realm Database does not automatically convert strings to ObjectIds.
The following example shows the correct and incorrect way to write a query with an ObjectId given the following Realm object:
class User: Object { @objc dynamic var id = ObjectId.generate() @objc dynamic var name = "" }
let realm = try! Realm() let users = realm.objects(User.self) // Get specific user by ObjectId id let specificUser = users.filter("id = %@", ObjectId("11223344556677889900aabb")).first // WRONG: Realm will not convert the string to an object id // users.filter("id = '11223344556677889900aabb'") // not ok // users.filter("id = %@", "11223344556677889900aabb") // not ok
Sort Query Results¶
A sort operation allows you to configure the order in which Realm Database returns queried objects. You can sort based on one or more properties of the objects in the results collection. Realm Database only guarantees a consistent order of results if you explicitly sort them.
To sort, call Results.sorted(byKeyPath:ascending:) with the desired key path to sort by.
let realm = try! Realm() // Access all dogs in the realm let dogs = realm.objects(Dog.self) let dogsSorted = dogs.sorted(byKeyPath: "name", ascending: false) // You can also sort on the members of linked objects. In this example, // we sort the dogs by their favorite toys' names. let dogsSortedByFavoriteToyName = dogs.sorted(byKeyPath: "favoriteToy.name")
To sort a query based on a property of an embedded object or a related object, use dot-notation as if it were in a regular, nested object.
Query a Relationship¶
You can query through a relationship the same way you would access a member of a regular Swift or Objective-C object.
let realm = try! Realm() // Establish a relationship let dog = Dog() dog.name = "Rex" dog.age = 10 let person = Person() person.id = 12345 person.dogs.append(dog) try! realm.write { realm.add(person) } // Later, query the specific person let specificPerson = realm.object(ofType: Person.self, forPrimaryKey: 12345) // Access directly through a relationship let specificPersonDogs = specificPerson!.dogs let firstDog = specificPersonDogs[0] print("# dogs: \(specificPersonDogs.count)") print("First dog's name: \(firstDog.name)")
Query an Inverse Relationship¶
You can query through an inverse relationship the same way you would access a member of a regular Swift or Objective-C object.
let realm = try! Realm() // Establish an inverse relationship let person = Person() person.id = 12345 let club = DogClub() club.name = "Pooch Pals" club.members.append(person) try! realm.write { realm.add(club) } // Later, query the specific person let specificPerson = realm.object(ofType: Person.self, forPrimaryKey: 12345) // Access directly through an inverse relationship let clubs = specificPerson!.clubs let firstClub = clubs[0] print("# memberships: \(clubs.count)") print("First club's name: \(firstClub.name)")
Aggregate Data¶
You can use Realm's aggregation operators for sophisticated queries against list properties.
let realm = try! Realm() let people = realm.objects(Person.self) // People whose dogs' average age is 5 people.filter("dogs.@avg.age == 5") // People with older dogs people.filter("dogs.@min.age > 5") // People with younger dogs people.filter("dogs.@max.age < 2") // People with many dogs people.filter("dogs.@count > 2") // People whose dogs' ages combined > 10 years people.filter("dogs.@sum.age > 10")
Chain Queries¶
Because results are lazily evaluated, you can chain several queries together. Unlike traditional databases, this does not require a separate trip to the database for each successive query.
To get a result set for tan dogs, and tan dogs whose names start with ‘B’, chain two queries like this:
let realm = try! Realm() let tanDogs = realm.objects(Dog.self).filter("color = 'tan'") let tanDogsWithBNames = tanDogs.filter("name BEGINSWITH 'B'")
Write Operations¶
Create a New Object¶
To add an object to a realm, instantiate it as you would any other object and then pass it to Realm.add(_:update:) inside of a write transaction.
// Instantiate the class. For convenience, you can initialize // objects from dictionaries with appropriate keys and values. let dog = Dog(value: ["name": "Max", "age": 5]) let realm = try! Realm() // Open a thread-safe transaction. try! realm.write { // Add the instance to the realm. realm.add(dog) }
Initialize Objects with a Value¶
You can initialize an object by passing an initializer value to Object.init(value:). The initializer value can be a key-value coding compliant object, a dictionary, or an array containing one element for each managed property.
When using an array as an initializer value, you must include all properties in the same order as they are defined in the model.
You can even initialize related or embedded objects by nesting initializer values:
// Instead of using pre-existing dogs... let aPerson = Person(value: [123, "Jane", [aDog, anotherDog]]) // ...we can create them inline let anotherPerson = Person(value: [123, "Jane", [["Buster", 5], ["Buddy", 6]]])
Create an Object with JSON¶
Realm does not directly support JSON, but you can use JSONSerialization.jsonObject(with:options:) to convert JSON into a value that you can pass to Realm.create(_:value:update:).
// Specify a dog toy in JSON let data = "{\"name\": \"Tennis ball\"}".data(using: .utf8)! let realm = try! Realm() // Insert from data containing JSON try! realm.write { let json = try! JSONSerialization.jsonObject(with: data, options: []) realm.create(DogToy.self, value: json) }
Nested objects or arrays in the JSON map to to-one or to-many relationships.
The JSON property names and types must match the destination object schema exactly. For example:
float
properties must be initialized with float-backedNSNumbers
.Date
andData
properties cannot be inferred from strings. Convert them to the appropriate type before passing to Realm.create(_:value:update:).- Required properties cannot be
null
or missing in the JSON.
Realm ignores any properties in the JSON not defined in the object schema.
If your JSON schema doesn't exactly align with your Realm objects, consider using a third-party framework to transform your JSON. There are many model mapping frameworks that work with Realm. See a partial list in the realm-cocoa repository.
Copy an Object to Another Realm¶
To copy an object from one realm to another, pass the original object to Realm.create(_:value:update:)::
let realm = try! Realm(configuration: Realm.Configuration(inMemoryIdentifier: "first realm")) try! realm.write { let dog = Dog() dog.name = "Wolfie" dog.age = 1 realm.add(dog) } // Later, fetch the instance we want to copy let wolfie = realm.objects(Dog.self).first(where: { $0.name == "Wolfie" })! // Open the other realm let otherRealm = try! Realm(configuration: Realm.Configuration(inMemoryIdentifier: "second realm")) try! otherRealm.write { // Copy to the other realm let wolfieCopy = otherRealm.create(type(of: wolfie), value: wolfie) wolfieCopy.age = 2 // Verify that the copy is separate from the original XCTAssertNotEqual(wolfie.age, wolfieCopy.age) }
The create
methods do not support handling cyclical object
graphs. Do not pass in an object containing relationships involving
objects that refer back to their parents, either directly or
indirectly.
Modify an Object¶
You can modify properties of a Realm object inside of a write transaction in the same way that you would update any other Swift or Objective-C object.
let realm = try! Realm() // Get a dog to update let dog = realm.objects(Dog.self).first! // Open a thread-safe transaction try! realm.write { // Update some properties on the instance. // These changes are saved to the realm dog.name = "Wolfie" dog.age += 1 }
To update a property of an embedded object or a related object, modify the property with dot-notation or bracket-notation as if it were in a regular, nested object.
Update Properties with Key-value Coding¶
Object
, Result
, and List
all conform to
key-value coding.
This can be useful when you need to determine which property to update
at runtime.
Applying KVC to a collection is a great way to update objects in bulk. Avoid the overhead of iterating over a collection while creating accessors for every item.
let realm = try! Realm() let allDogs = realm.objects(Dog.self) try! realm.write { allDogs.first?.setValue("Sparky", forKey: "name") // Move the dogs to Toronto for vacation allDogs.setValue("Toronto", forKey: "currentCity") }
You can also add values for embedded objects or relationships this way. See Initialize Objects with a Value.
Upsert an Object¶
To upsert an object, call Realm.add(_:update:)
with the second parameter, update policy, set to .modified
.
The operation either inserts a new object with the given primary
key or updates an existing object that already has that primary
key.
let realm = try! Realm() try! realm.write { let person1 = Person(value: ["id": 1234, "name": "Jones"]) // 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(person1, update: .modified) let person2 = Person(value: ["id": 1234, "name": "Bowie"]) // 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(person2, update: .modified) }
Delete an Object¶
To delete an object from a realm, pass the object to Realm.delete(_:) inside of a write transaction.
try! realm.write { // Delete the instance from the realm. realm.delete(dog) }
You cannot access or modify an object after you have deleted it from a realm. If you try to use a deleted object, Realm Database throws an error.
Delete Multiple Objects¶
To delete a collection of objects from a realm, pass the collection to Realm.delete(_:) inside of a write transaction.
let realm = try! 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) }
Delete All Objects of a Specific Type¶
To delete all objects of a given object type from a realm, pass the result of Realm.objects(_:) for the type you wish to delete to Realm.delete(_:) inside of a write transaction.
let realm = try! Realm() try! realm.write { // Delete all instances of Dog from the realm. let allDogs = realm.objects(Dog.self) realm.delete(allDogs) }
Delete All Objects in a Realm¶
To delete all objects from the realm, call Realm.deleteAll() inside of a write transaction. This clears the realm of all object instances but does not affect the realm's schema.
let realm = try! Realm() try! realm.write { // Delete all objects from the realm. realm.deleteAll() }