Leer desde un reino
Una lectura de un reino generalmente consta de los siguientes pasos:
Obtener todos los objetos de un determinado tipo del reino.
Opcionalmente, filtrar los resultados.
Opcionalmente, ordenar los resultados.
Como alternativa, puede obtener todos los objetos de un tipo determinado, divididos en secciones. Al igual que con los resultados normales, puede filtrar y ordenar los resultados seccionados.
Las operaciones de consulta, filtrado y ordenación devuelven una colección de resultados o de SectionedResults. Estas colecciones están activas, lo que significa que siempre contienen los resultados más recientes de la consulta asociada.
Leer Características
Cuando diseña los patrones de acceso a datos de su aplicación en torno a las siguientes tres características clave de lectura en Realm, puede estar seguro de que está leyendo los datos de la manera más eficiente posible.
Los resultados no son copias
Los resultados de una consulta no son copias de sus datos: modificarlos modificará directamente los datos en el disco. Esta asignación de memoria también significa que los resultados están en tiempo real, es decir, siempre reflejan el estado actual del disco.
Ver también: Las colecciones están activas.
Los resultados son perezosos
Realm solo ejecuta una consulta cuando se solicitan los resultados. Esta evaluación diferida permite escribir código elegante y de alto rendimiento para gestionar grandes conjuntos de datos y consultas complejas. Se pueden encadenar varias operaciones de filtrado y ordenación sin necesidad de procesar el estado intermedio.
Se conservan las referencias
Una ventaja del modelo de objetos de Realm es que Realm conserva automáticamente todas las relaciones de un objeto como referencias directas, de modo que puede recorrer su gráfico de relaciones directamente a través de los resultados de una consulta.
Una referencia directa, o puntero, te permite acceder directamente a las propiedades de un objeto relacionado a través de la referencia.
Otras bases de datos suelen copiar objetos del almacenamiento de la base de datos a la memoria de la aplicación cuando necesitas trabajar directamente con ellos. Debido a que los objetos de la aplicación contienen referencias directas, tienes la siguiente opción: copiar el objeto al que se hace referencia en cada referencia directa fuera de la base de datos en caso de que sea necesario, o simplemente copiar la clave externa de cada objeto y hacer query para el objeto con esa clave si se accede a él. Si eliges copiar objetos referenciados a la memoria de la aplicación, puedes usar muchos recursos para objetos a los que nunca se accede, pero si elige solo copiar la clave externa, las búsquedas de objetos referenciados pueden causar que su aplicación se vuelva lenta.
Realm evita todo esto mediante objetos activos de copia cero. Los accesos a objetos de Realm apuntan directamente al almacenamiento de la base de datos mediante mapeo de memoria, por lo que no hay distinción entre los objetos en Realm y los resultados de la consulta en la memoria de la aplicación. Gracias a esto, se pueden recorrer referencias directas en todo un reino desde cualquier resultado de consulta.
Limitar los resultados de la consulta
Gracias a la evaluación diferida, no se necesita ningún mecanismo especial para limitar los resultados de las consultas con Realm. Por ejemplo, si la consulta coincide con miles de objetos, pero solo se desea cargar los diez primeros, simplemente se accede únicamente a los diez primeros elementos de la colección de resultados.
Paginación
Gracias a la evaluación diferida, la tarea habitual de paginación se simplifica considerablemente. Por ejemplo, supongamos que tiene una colección de resultados asociada a una consulta que coincide con miles de objetos en su dominio. Muestra cien objetos por página. Para avanzar a cualquier página, simplemente acceda a los elementos de la colección de resultados comenzando por el índice correspondiente a la página de destino.
Leer objetos del reino
Acerca de los ejemplos en esta página
Los ejemplos de esta página utilizan los siguientes modelos:
// DogToy.h @interface DogToy : RLMObject @property NSString *name; @end // Dog.h @interface Dog : RLMObject @property NSString *name; @property int age; @property NSString *color; // To-one relationship @property DogToy *favoriteToy; @end // Enable Dog for use in RLMArray RLM_COLLECTION_TYPE(Dog) // Person.h // A person has a primary key ID, a collection of dogs, and can be a member of multiple clubs. @interface Person : RLMObject @property int _id; @property NSString *name; // To-many relationship - a person can have many dogs @property RLMArray<Dog *><Dog> *dogs; // Inverse relationship - a person can be a member of many clubs @property (readonly) RLMLinkingObjects *clubs; @end RLM_COLLECTION_TYPE(Person) // DogClub.h @interface DogClub : RLMObject @property NSString *name; @property RLMArray<Person *><Person> *members; @end // Dog.m @implementation Dog @end // DogToy.m @implementation DogToy @end // Person.m @implementation Person // Define the primary key for the class + (NSString *)primaryKey { return @"_id"; } // Define the inverse relationship to dog clubs + (NSDictionary *)linkingObjectsProperties { return @{ @"clubs": [RLMPropertyDescriptor descriptorWithClass:DogClub.class propertyName:@"members"], }; } @end // DogClub.m @implementation DogClub @end
class DogToy: Object { var id: ObjectId var name = "" } class Dog: Object { var name = "" var age = 0 var color = "" var currentCity = "" var citiesVisited: MutableSet<String> var companion: AnyRealmValue // To-one relationship var favoriteToy: DogToy? // Map of city name -> favorite park in that city var favoriteParksByCity: Map<String, String> // Computed variable that is not persisted, but only // used to section query results. var firstLetter: String { return name.first.map(String.init(_:)) ?? "" } } class Person: Object { (primaryKey: true) var id = 0 var name = "" // To-many relationship - a person can have many dogs var dogs: List<Dog> // Inverse relationship - a person can be a member of many clubs (originProperty: "members") var clubs: LinkingObjects<DogClub> // Embed a single object. // Embedded object properties must be marked optional. var address: Address? convenience init(name: String, address: Address) { self.init() self.name = name self.address = address } } class DogClub: Object { var name = "" var members: List<Person> // DogClub has an array of regional office addresses. // These are embedded objects. var regionalOfficeAddresses: List<Address> convenience init(name: String, addresses: [Address]) { self.init() self.name = name self.regionalOfficeAddresses.append(objectsIn: addresses) } } class Address: EmbeddedObject { var street: String? var city: String? var country: String? var postalCode: String? }
Buscar un objeto específico por clave primaria
Si conoce la clave principal de un objeto determinado, puede buscarla directamente con +[RLMObject objectForPrimaryKey:].
// Get a specific person from the default realm Person *specificPerson = [Person objectForPrimaryKey:@12345];
Si conoce la clave principal de un objeto determinado, puede buscarla directamente con Realm.object(ofType:forPrimaryKey:).
let realm = try! Realm() let specificPerson = realm.object(ofType: Person.self, forPrimaryKey: 12345)
Consultar todos los objetos de un tipo determinado
Para consultar objetos de un tipo determinado en un reino, pase la instancia del reino a +[YourRealmObjectClass allObjectsInRealm:]. Reemplace YourRealmObjectClass con el nombre de la clase de objeto Realm. Esto devuelve un objeto RLMResults que representa todos los objetos del tipo dado en el reino.
RLMRealm *realm = [RLMRealm defaultRealm]; RLMResults *dogs = [Dog allObjectsInRealm:realm]; RLMResults *people = [Person allObjectsInRealm:realm];
Para consultar objetos de un tipo determinado en un dominio, pase la instancia de metatipo YourClassName.self a Realm.objects(_:). Esto devuelve un objeto Results que representa todos los objetos del tipo dado en el dominio.
let realm = try! Realm() // Access all dogs in the realm let dogs = realm.objects(Dog.self)
Filtro de queries basadas en las propiedades del objeto
Un filtro selecciona un subconjunto de resultados según el valor de una o más propiedades del objeto. Realm proporciona un motor de consulta completo que permite definir filtros.
Nueva en la versión 10.19.0.
Para utilizar la API de consulta Swift de Realm, llame a .where con un cierre que contenga una expresión de consulta como argumento.
let realm = try! Realm() // Access all dogs in the realm let dogs = realm.objects(Dog.self) // Query by age let puppies = dogs.where { $0.age < 2 } // Query by person let dogsWithoutFavoriteToy = dogs.where { $0.favoriteToy == nil } // Query by person's name let dogsWhoLikeTennisBalls = dogs.where { $0.favoriteToy.name == "Tennis ball" }
Para filtrar, llame a Results.filter(_:) con un predicado de consulta.
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'")
Para filtrar, llame a -[RLMResults objectsWhere:] con un predicado de consulta.
RLMRealm *realm = [RLMRealm defaultRealm]; // Access all dogs in the realm RLMResults *dogs = [Dog allObjectsInRealm:realm]; // Filter by age RLMResults *puppies = [dogs objectsWhere:@"age < 2"]; // Filter by favorite toy RLMResults *dogsWithoutFavoriteToy = [dogs objectsWhere:@"favoriteToy == nil"]; // Filter by favorite toy's name RLMResults *dogsWhoLikeTennisBalls = [dogs objectsWhere:@"favoriteToy.name == %@", @"Tennis ball"];
Tip
Filtrar por propiedades de objetos relacionados e incrustados
Para filtrar una consulta en función de una propiedad de un objeto incrustado o un objeto relacionado, utilice la notación de puntos como si se tratara de un objeto anidado normal.
Filtrar por propiedades de ID de objeto
Los tipos de tu predicado deben coincidir con los tipos de las propiedades. Evita comparar ObjectId propiedades con cadenas, ya que Realm no convierte automáticamente las cadenas en ObjectIds.
Nueva en la versión 10.19.0.
La seguridad de tipos incorporada de la API de consulta Swift de Realm simplifica la escritura de una consulta con un ObjectId:
let realm = try! Realm() let dogToys = realm.objects(DogToy.self) // Get specific user by ObjectId id let specificToy = dogToys.where { $0.id == ObjectId("11223344556677889900aabb") }
El siguiente ejemplo muestra la forma correcta e incorrecta de escribir una consulta con un ObjectId dado el siguiente objeto Realm:
let realm = try! Realm() let dogToys = realm.objects(DogToy.self) // Get specific toy by ObjectId id let specificToy = dogToys.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
Consultar una relación
Puede realizar consultas a través de una relación de la misma manera que accedería a un miembro de un objeto Swift u Objective-C normal.
RLMRealm *realm = [RLMRealm defaultRealm]; // Establish a relationship Dog *dog = [[Dog alloc] init]; dog.name = @"Rex"; dog.age = 10; Person *person = [[Person alloc] init]; person._id = 12345; [person.dogs addObject:dog]; [realm transactionWithBlock:^() { [realm addObject:person]; }]; // Later, query the specific person Person *specificPerson = [Person objectForPrimaryKey:@12345]; // Access directly through a relationship NSLog(@"# dogs: %lu", [specificPerson.dogs count]); NSLog(@"First dog's name: %@", specificPerson.dogs[0].name);
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)")
Consultar una relación inversa
Puede realizar consultas a través de una relación inversa de la misma manera que accedería a un miembro de un objeto Swift u Objective-C normal.
RLMRealm *realm = [RLMRealm defaultRealm]; // Establish a relationship Person *person = [[Person alloc] init]; person._id = 12345; DogClub *club = [[DogClub alloc] init]; club.name = @"Pooch Pals"; [club.members addObject:person]; [realm transactionWithBlock:^() { [realm addObject:club]; }]; // Later, query the specific person Person *specificPerson = [Person objectForPrimaryKey:@12345]; // Access directly through an inverse relationship NSLog(@"# memberships: %lu", [specificPerson.clubs count]); NSLog(@"First club's name: %@", [specificPerson.clubs[0] name]);
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)")
Consultar una colección sobre las propiedades de un objeto incrustado
Utilice la notación de puntos para filtrar u ordenar una colección de objetos según el valor de una propiedad de objeto incrustado:
Nota
No es posible consultar objetos incrustados directamente. En su lugar, acceda a los objetos incrustados mediante una query para el tipo de objeto Realm.
Nueva en la versión 10.19.0.
// Open the default realm let realm = try! Realm() // Get all contacts in Los Angeles, sorted by street address let losAngelesPeople = realm.objects(Person.self) .where { $0.address.city == "Los Angeles" } .sorted(byKeyPath: "address.street") print("Los Angeles Person: \(losAngelesPeople)")
// Open the default realm let realm = try! Realm() // Get all people in Los Angeles, sorted by street address let losAngelesPeople = realm.objects(Person.self) .filter("address.city = %@", "Los Angeles") .sorted(byKeyPath: "address.street") print("Los Angeles Person: \(losAngelesPeople)")
RLMRealm *realm = [RLMRealm defaultRealm]; RLMResults<Contact *> *losAngelesContacts = [Contact objectsInRealm:realm where:@"address.city = %@", @"Los Angeles"]; losAngelesContacts = [losAngelesContacts sortedResultsUsingKeyPath:@"address.street" ascending:YES]; NSLog(@"Los Angeles Contacts: %@", losAngelesContacts);
Consultar una propiedad de mapa
Puede iterar y verificar los valores de un mapa de reino como lo haría con un diccionario estándar:
let realm = try! Realm() let dogs = realm.objects(Dog.self) // Find dogs who have favorite parks let dogsWithFavoriteParks = dogs.where { $0.favoriteParksByCity.count >= 1 } for dog in dogsWithFavoriteParks { // Check if an entry exists if dog.favoriteParksByCity.keys.contains("Chicago") { print("\(dog.name) has a favorite park in Chicago") } // Iterate over entries for element in dog.favoriteParksByCity { print("\(dog.name)'s favorite park in \(element.key) is \(element.value)") } }
Query una propiedad MutableSet
Puedes consultar un MutableSet para comprobar si contiene un elemento. Si trabajas con varios conjuntos, puedes comprobar la intersección de dos o si un conjunto es un subconjunto del otro.
let realm = try! Realm() // Find dogs who have visited New York let newYorkDogs = realm.objects(Dog.self).where { $0.citiesVisited.contains("New York") } // Get some information about the cities they have visited for dog in newYorkDogs { print("Cities \(dog.name) has visited: \(dog.citiesVisited)") } // Check whether two dogs have visited some of the same cities. // Use "intersects" to find out whether the values of the two sets share common elements. let isInBothCitiesVisited = (dog.citiesVisited.intersects(dog2.citiesVisited)) print("The two dogs have visited some of the same cities: \(isInBothCitiesVisited)") // Prints "The two dogs have visited some of the same cities: true" // Or you can check whether a set is a subset of another set. In this example, // the first dog has visited "New York" and "Toronto", while dog2 has visited both of // those but also "Toronto" and "Boston". let isSubset = (dog.citiesVisited.isSubset(of: dog2.citiesVisited)) print("\(dog.name)'s set of cities visited is a subset of \(dog2.name)'s: \(isSubset)") // Prints "Maui's set of cities visited is a subset of Lita's: true"
Leer y query cualquier propiedad AnyRealmValue
Al leer una propiedad AnyRealmValue, verifique el tipo del valor antes de realizar cualquier acción. El SDK de Realm Swift proporciona una enumeración AnyRealmValue que itera sobre todos los tipos que AnyRealmValue puede almacenar.
let realm = try! Realm() let dogs = realm.objects(Dog.self) for dog in dogs { // Verify the type of the ``AnyRealmProperty`` when attempting to get it. This // returns an object whose property contains the matched type. // If you only care about one type, check for that type. if case let .string(companion) = dog.companion { print("\(dog.name)'s companion is: \(companion)") // Prints "Wolfie's companion is: Fluffy the Cat" } // Or if you want to do something with multiple types of data // that could be in the value, switch on the type. switch dog.companion { case .string: print("\(dog.name)'s companion is: \(dog.companion)") // Prints "Wolfie's companion is: string("Fluffy the Cat") case .object: print("\(dog.name)'s companion is: \(dog.companion)") // Prints "Fido's companion is: object(Dog { name = Spot })" case .none: print("\(dog.name) has no companion") // Prints "Rex has no companion" and "Spot has no companion" default: print("\(dog.name)'s companion is another type.") } }
Puede comparar estos tipos de valores mixtos:
Numérico: int, bool, float, double, decimal
Basado en bytes: cadena, binario
Basado en el tiempo: timestamp, objectId
Al utilizar el tipo de datos mixto AnyRealmValue, tenga en cuenta lo siguiente:
equalsLas consultas coinciden en valor y tiponot equalsLas consultas coinciden con objetos con diferentes valores o diferentes tiposrealm convierte propiedades numéricas comparables siempre que sea posible. Por ejemplo, en un campo de tipo mixto, 1 coincide con todo 1.0, 1 y true.
Las propiedades de cadena no coinciden con las consultas numéricas. Por ejemplo, en un campo de tipo mixto, 1 no coincide con "1". "1" no coincide con 1, 1.0 ni con "true".
Consultar datos geoespaciales
Nuevo en la versión 10.47.0.
El SDK de Swift proporciona varias formas para simplificar la consulta de datos geoespaciales. Puede usar las GeoCircle formas, GeoBox y GeoPolygon para definir los límites de sus consultas de datos geoespaciales.
El SDK proporciona dos tipos de datos especializados no persistentes para definir formas:
GeoPoint:Una estructura que representa las coordenadas de un punto formado por un par de dobles que constan de estos valores:Latitud: varía entre -90 y 90 grados, inclusive.
Longitud: varía entre -180 y 180 grados, inclusive.
RLMDistance:Una estructura auxiliar para representar y convertir una distancia.
Definir formas geoespaciales
Un GeoCircle es una forma circular cuyos límites se originan en un GeoPoint central y su tamaño corresponde a un radio medido en radianes. Puede usar el tipo de dato RLMDistance del SDK para trabajar fácilmente con radios en diferentes unidades.
RLMDistance permite especificar la distancia del radio para las formas geográficas en una de cuatro unidades:
.degrees.kilometers.miles.radians
Opcionalmente, puede utilizar los métodos de conveniencia suministrados para convertir una medida a una unidad de distancia diferente.
// You can create a GeoCircle radius measured in radians. // This radian distance corresponds with 0.25 degrees. let smallCircle = GeoCircle(center: (47.3, -121.9), radiusInRadians: 0.004363323) // You can also create a GeoCircle radius measured with a Distance. // You can specify a Distance in .degrees, .kilometers, .miles, or .radians. let largeCircle = GeoCircle(center: GeoPoint(latitude: 47.8, longitude: -122.6)!, radius: Distance.kilometers(44.4)!)

Un GeoBox es una forma rectangular cuyos límites están determinados por las coordenadas de una esquina inferior izquierda y una esquina superior derecha.
let largeBox = GeoBox(bottomLeft: (47.3, -122.7), topRight: (48.1, -122.1)) let smallBoxBottomLeft = GeoPoint(latitude: 47.5, longitude: -122.4)! let smallBoxTopRight = GeoPoint(latitude: 47.9, longitude: -121.8) let smallBox = GeoBox(bottomLeft: smallBoxBottomLeft, topRight: smallBoxTopRight!)

Un GeoPolygon es una forma poligonal cuyos límites consisten en un anillo exterior y 0 o más agujeros internos para excluir de la consulta geoespacial.
El anillo exterior de un polígono debe contener al menos tres segmentos. El último y el primer GeoPoint deben ser iguales, lo que indica un polígono cerrado. Esto significa que se necesitan al menos cuatro valores GeoPoint para construir un polígono.
Los agujeros internos de un GeoPolygon deben estar completamente contenidos dentro del anillo exterior.
Los agujeros tienen las siguientes restricciones:
Los agujeros no pueden cruzarse. El límite de un agujero no puede intersecar el interior ni el exterior de ningún otro agujero.
Los agujeros no pueden compartir aristas. Si un agujero tiene una arista AB, ningún otro agujero puede contenerla.
Los agujeros pueden compartir vértices. Sin embargo, ningún vértice puede aparecer dos veces en un mismo agujero.
Ningún agujero puede estar vacío.
Sólo se permite una anidación.
// Create a basic polygon let basicPolygon = GeoPolygon(outerRing: [ (48.0, -122.8), (48.2, -121.8), (47.6, -121.6), (47.0, -122.0), (47.2, -122.6), (48.0, -122.8) ]) // Create a polygon with one hole let outerRing: [GeoPoint] = [ GeoPoint(latitude: 48.0, longitude: -122.8)!, GeoPoint(latitude: 48.2, longitude: -121.8)!, GeoPoint(latitude: 47.6, longitude: -121.6)!, GeoPoint(latitude: 47.0, longitude: -122.0)!, GeoPoint(latitude: 47.2, longitude: -122.6)!, GeoPoint(latitude: 48.0, longitude: -122.8)! ] let hole: [GeoPoint] = [ GeoPoint(latitude: 47.8, longitude: -122.6)!, GeoPoint(latitude: 47.7, longitude: -122.2)!, GeoPoint(latitude: 47.4, longitude: -122.6)!, GeoPoint(latitude: 47.6, longitude: -122.5)!, GeoPoint(latitude: 47.8, longitude: -122.6)! ] let polygonWithOneHole = GeoPolygon(outerRing: outerRing, holes: [hole]) // Add a second hole to the polygon let hole2: [GeoPoint] = [ GeoPoint(latitude: 47.55, longitude: -122.05)!, GeoPoint(latitude: 47.55, longitude: -121.9)!, GeoPoint(latitude: 47.3, longitude: -122.1)!, GeoPoint(latitude: 47.55, longitude: -122.05)! ] let polygonWithTwoHoles = GeoPolygon(outerRing: outerRing, holes: [hole, hole2])

Consulta con formas geoespaciales
Puede usar estas formas en una consulta geoespacial. Puede consultar datos geoespaciales de tres maneras:
Uso del operador
.geoWithin()con la API de consulta Swift de Realm con seguridad de tiposUsando un
.filter()con RQLUsando un
.filter()con una consulta NSPredicate
Los ejemplos a continuación muestran los resultados de las consultas que utilizan estos dos objetos Company:
let company1 = Geospatial_Company() company1.location = CustomGeoPoint(47.68, -122.35) let company2 = Geospatial_Company(CustomGeoPoint(47.9, -121.85))

let companiesInSmallCircle = realm.objects(Geospatial_Company.self).where { $0.location.geoWithin(smallCircle!) } print("Number of companies in small circle: \(companiesInSmallCircle.count)") let companiesInLargeCircle = realm.objects(Geospatial_Company.self) .filter("location IN %@", largeCircle) print("Number of companies in large circle: \(companiesInLargeCircle.count)")

let companiesInSmallBox = realm.objects(Geospatial_Company.self).where { $0.location.geoWithin(smallBox) } print("Number of companies in small box: \(companiesInSmallBox.count)") let filterArguments = NSMutableArray() filterArguments.add(largeBox) let companiesInLargeBox = realm.objects(Geospatial_Company.self) .filter(NSPredicate(format: "location IN %@", argumentArray: filterArguments as? [Any])) print("Number of companies in large box: \(companiesInLargeBox.count)")

let companiesInBasicPolygon = realm.objects(Geospatial_Company.self).where { $0.location.geoWithin(basicPolygon!) } print("Number of companies in basic polygon: \(companiesInBasicPolygon.count)") let companiesInPolygonWithTwoHoles = realm.objects(Geospatial_Company.self).where { $0.location.geoWithin(polygonWithTwoHoles!) } print("Number of companies in polygon with two holes: \(companiesInPolygonWithTwoHoles.count)")

Consultar una propiedad persistente personalizada
Cuando se utiliza la proyección de tipos para asignar tipos no admitidos a tipos admitidos, el acceso a esas propiedades a menudo se basa en el tipo persistido.
Consultas sobre objetos de Realm
Al trabajar con tipos proyectados, las consultas operan sobre el tipo persistente. Sin embargo, en la mayoría de los casos, los tipos mapeados y los tipos persistentes se pueden usar indistintamente en los argumentos. La excepción son las consultas sobre objetos incrustados.
Tip
Los tipos proyectados admiten ordenamiento y agregaciones donde el tipo persistente los admite.
let akcClub = realm.objects(Club.self).where { $0.name == "American Kennel Club" }.first! // You can use type-safe expressions to check for equality XCTAssert(akcClub.url == URL(string: "https://akc.org")!) let clubs = realm.objects(Club.self) // You can use the persisted property type in NSPredicate query expressions let akcByUrl = clubs.filter("url == 'https://akc.org'").first! XCTAssert(akcByUrl.name == "American Kennel Club")
Consultas sobre objetos incrustados
Puede consultar tipos incrustados en los tipos de propiedad admitidos dentro del objeto utilizando igualdad entre miembros.
Las propiedades de enlace de objetos admiten comparaciones de igualdad, pero no comparaciones miembro por miembro. Se pueden consultar objetos incrustados para determinar la igualdad miembro por miembro en todos los tipos primitivos. No se pueden realizar comparaciones miembro por miembro en objetos y colecciones.
APIs dinámicas
Dado que el esquema no admite asignaciones de tipos personalizadas, la lectura de datos mediante cualquiera de las API dinámicas proporciona el tipo persistente subyacente. Realm admite la escritura de tipos asignados mediante una API dinámica y convierte el tipo proyectado al tipo persistente.
El uso más común de las API dinámicas es la migración. Se pueden escribir tipos proyectados durante la migración, y Realm convierte el tipo proyectado al tipo persistente. Sin embargo, al leer datos durante una migración, se obtiene el tipo persistente subyacente.
Leer un objeto de forma asincrónica
Cuando utiliza un ámbito aislado de actores, puede usar las funciones de concurrencia de Swift para consultar objetos de forma asincrónica.
let actor = try await RealmActor() // Read objects in functions isolated to the actor and pass primitive values to the caller func getObjectId(in actor: isolated RealmActor, forTodoNamed name: String) async -> ObjectId { let todo = actor.realm.objects(Todo.self).where { $0.name == name }.first! return todo._id } let objectId = await getObjectId(in: actor, forTodoNamed: "Keep it safe")
Si necesita avanzar manualmente el estado de un dominio observado en el hilo principal o en un dominio aislado por un actor, llame a await realm.asyncRefresh(). Esto actualiza el dominio y los objetos pendientes administrados por este para que apunten a los datos más recientes y envíen las notificaciones pertinentes.
Para obtener más información sobre cómo trabajar con Realm usando las funciones de concurrencia de Swift, consulte Usar Realm con actores - Swift SDK.
Ordene los resultados del query
Una operación de ordenación permite configurar el orden en que Realm Database devuelve los objetos consultados. Puede ordenarlos según una o más propiedades de los objetos de la colección de resultados. Realm solo garantiza un orden coherente de los resultados si los ordena explícitamente.
Para ordenar, llame a -[RLMResults sortedResultsUsingKeyPath:ascending:] con la ruta de clave deseada para ordenar.
RLMRealm *realm = [RLMRealm defaultRealm]; RLMResults *dogs = [Dog allObjectsInRealm:realm]; // Sort dogs by name RLMResults *dogsSorted = [dogs sortedResultsUsingKeyPath:@"name" ascending:NO]; // You can also sort on the members of linked objects. In this example, // we sort the dogs by their favorite toys' names. RLMResults *dogsSortedByFavoriteToyName = [dogs sortedResultsUsingKeyPath:@"favoriteToy.name" ascending:YES];
Nuevo en la versión 10.11.0.
Puede ordenar utilizando la clave keyPath de tipo seguro llamando a Results.sorted(by: ) con el nombre de keyPath y el orden de clasificación opcional:
let realm = try! Realm() // Access all dogs in the realm let dogs = realm.objects(Dog.self) // Sort by type-safe keyPath let dogsSorted = dogs.sorted(by: \.name)
Para ordenar utilizando la API anterior, llame a Results.sorted(byKeyPath:ascending:) con la ruta de clave deseada por la que ordenar.
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")
Tip
Ordenar por propiedades de objetos relacionados e incrustados
Para ordenar una query basada en una propiedad de un objeto incrustado o un objeto relacionado, usa notación de puntos como si fuera un objeto anidado regular.
Nota
La ordenación de cadenas y las consultas sin distinción entre mayúsculas y minúsculas solo se admiten para los conjuntos de caracteres en 'Latin Basic', 'Latin Supplement', 'Latin Extended A' y 'Latin Extended B' (UTF-8 rango 0-591).
Resultados de la consulta de sección
Puedes dividir los resultados en secciones individuales. Cada sección corresponde a una clave generada a partir de una propiedad del objeto que representa.
Por ejemplo, puede agregar una variable calculada a su objeto para obtener la primera letra de la propiedad name:
// Computed variable that is not persisted, but only // used to section query results. var firstLetter: String { return name.first.map(String.init(_:)) ?? "" }
Luego, puedes crear una colección de tipo seguro SectionedResults para ese objeto y usarla para recuperar objetos seccionados por esa variable calculada:
var dogsByFirstLetter: SectionedResults<String, Dog> dogsByFirstLetter = realm.objects(Dog.self).sectioned(by: \.firstLetter, ascending: true)
Puede obtener un recuento de las secciones, obtener una lista de claves o acceder a una ResultSection individual por índice:
let realm = try! Realm() var dogsByFirstLetter: SectionedResults<String, Dog> dogsByFirstLetter = realm.objects(Dog.self).sectioned(by: \.firstLetter, ascending: true) // You can get a count of the sections in the SectionedResults let sectionCount = dogsByFirstLetter.count // Get an array containing all section keys for objects that match the query. let sectionKeys = dogsByFirstLetter.allKeys // This example realm contains 4 dogs, "Rex", "Wolfie", "Fido", "Spot". // Prints ["F", "R", "S", "W"] print(sectionKeys) // Get a specific key by index position let sectionKey = dogsByFirstLetter[0].key // Prints "Key for index 0: F" print("Key for index 0: \(sectionKey)") // You can access Results Sections by the index of the key you want in SectionedResults. // "F" is the key at index position 0. When we access this Results Section, we get dogs whose name begins with "F". let dogsByF = dogsByFirstLetter[0] // Prints "Fido" print(dogsByF.first?.name)
También puedes seccionar mediante una devolución de llamada. Esto te permite seccionar una colección de primitivas o tener más control sobre cómo se genera la clave de sección.
let realm = try! Realm() let results = realm.objects(Dog.self) let sectionedResults = results.sectioned(by: { String($0.name.first!) }, sortDescriptors: [SortDescriptor.init(keyPath: "name", ascending: true)]) let sectionKeys = sectionedResults.allKeys
Puedes observar SectionedResults y ResultsSection instancias, y ambas cumplen con ThreadConfined.
Datos agregados
Puede utilizar los operadores de agregación de Realm para realizar consultas sofisticadas sobre propiedades de lista.
Nueva en la versión 10.19.0.
let realm = try! Realm() let people = realm.objects(Person.self) // People whose dogs' average age is 5 people.where { $0.dogs.age.avg == 5 } // People with older dogs people.where { $0.dogs.age.min > 5 } // People with younger dogs people.where { $0.dogs.age.max < 2 } // People with many dogs people.where { $0.dogs.count > 2 } // People whose dogs' ages combined > 10 years people.where { $0.dogs.age.sum > 10 }
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")
RLMRealm *realm = [RLMRealm defaultRealm]; RLMResults *people = [Person allObjectsInRealm:realm]; // People whose dogs' average age is 5 [people objectsWhere:@"dogs.@avg.age == 5"]; // People with older dogs [people objectsWhere:@"dogs.@min.age > 5"]; // People with younger dogs [people objectsWhere:@"dogs.@max.age < 2"]; // People with many dogs [people objectsWhere:@"dogs.@count > 2"]; // People whose dogs' ages combined > 10 years [people objectsWhere:@"dogs.@sum.age > 10"];
Consultas en cadena
Dado que los resultados se evalúan de forma diferida, se pueden encadenar varias consultas. A diferencia de las bases de datos tradicionales, esto no requiere una visita independiente a la base de datos para cada consulta sucesiva.
Ejemplo
Para obtener un conjunto de resultados para perros de color canela y perros de color canela cuyos nombres comienzan con 'B', encadene dos consultas de esta manera:
Nueva en la versión 10.19.0.
let realm = try! Realm() let tanDogs = realm.objects(Dog.self).where { $0.color == "tan" } let tanDogsWithBNames = tanDogs.where { $0.name.starts(with: "B") }
let realm = try! Realm() let tanDogs = realm.objects(Dog.self).filter("color = 'tan'") let tanDogsWithBNames = tanDogs.filter("name BEGINSWITH 'B'")
RLMRealm *realm = [RLMRealm defaultRealm]; RLMResults<Dog *> *tanDogs = [Dog objectsInRealm:realm where:@"color = 'tan'"]; RLMResults<Dog *> *tanDogsWithBNames = [tanDogs objectsWhere:@"name BEGINSWITH 'B'"];
Proyecciones de clases de consulta
Para consultar las proyecciones de clase en un dominio, pase la instancia de metatipo YourProjectionName.self a Realm.objects(_:). Esto devuelve un objeto Results que representa todos los objetos de proyección de clase en el dominio.
// Retrieve all class projections of the given type `PersonProjection` let people = realm.objects(PersonProjection.self) // Use projection data in your view print(people.first?.firstName) print(people.first?.homeCity) print(people.first?.firstFriendsName)
Tip
No realice consultas derivadas sobre los resultados de la proyección de clase. En su lugar, ejecute una consulta directamente sobre el objeto Realm y luego proyecte el resultado. Si intenta realizar una consulta derivada sobre los resultados de la proyección de clase, consultar un campo con el mismo nombre y tipo que el objeto original funciona, pero consultar un campo con un nombre o tipo que no esté en el objeto original falla.