Menu Docs

CRUD — Leia — Swift SDK

Uma leitura de um reino geralmente consiste nas seguintes etapas:

  • Obtenha todos os objetos de um determinado tipo do realm.

  • Opcionalmente, filtre os resultados.

  • Opcionalmente, classifica os resultados.

  • Como alternativa, obtenha todos os objetos de um determinado tipo, divididos em seções. Tal como acontece com os resultados regulares, você pode filtrar e classificar os resultados seccionados.

As operações de consulta, filtro e classificação retornam uma coleção SectionedResults ou SectionedResults. Essas coleções estão ativas, o que significa que elas sempre contêm os resultados mais recentes da consulta associada.

Quando você projeta os padrões de acesso a dados da sua aplicação em torno das três principais características de leituras a seguir no Realm, você pode ter certeza de que está lendo dados da forma mais eficiente possível.

Os resultados de uma consulta não são cópias de seus dados: a modificação dos resultados de uma consulta modificará diretamente os dados no disco. Esse mapeamento de memória também significa que os resultados são ativos: ou seja, eles sempre refletem o estado atual no disco.

Veja também: As coleções são ao vivo.

O Realm só executa uma consulta quando você realmente solicita os resultados dessa consulta. Essa avaliação preguiçosa permite que você escreva código elegante e de alto desempenho para lidar com grandes conjuntos de dados e consultas complexas. Você pode encadear várias operações de filtro e classificação sem exigir trabalho extra para processar o estado intermediário.

Uma vantagem do modelo de objeto de Realm é que ele retém automaticamente todos os relacionamentos de um objeto como referências diretas, portanto você pode percorrer o grafo de relacionamentos diretamente por meio dos resultados de uma consulta.

Uma referência direta, ou ponteiro, permite que você acesse diretamente as propriedades de um objeto relacionado por meio da referência.

Outros bancos de dados geralmente copiam objetos do armazenamento do banco de dados para a memória do aplicativo quando você precisa trabalhar com eles diretamente. Como os objetos do aplicativo contêm referências diretas, você tem uma opção: copiar o objeto referido por cada referência direta para fora do banco de dados, caso seja necessário, ou apenas copiar a chave estrangeira de cada objeto e consultar o objeto com essa chave, se ele for acessado. Se você optar por copiar os objetos referenciados para a memória do aplicativo, poderá usar muitos recursos para objetos que nunca são acessados, mas se optar por copiar apenas a chave estrangeira, as pesquisas de objetos referenciados poderão causar lentidão no aplicativo.

O Realm contorna tudo isso com objetos ativos de cópia zero. Os acessadores de objeto de realm apontam diretamente para o armazenamento de banco de dados usando o mapeamento de memória, portanto não há distinção entre os objetos no Realm e os resultados da consulta na memória do aplicativo. Por isso você pode percorrer referências diretas em um domínio inteiro a partir de qualquer resultado de consulta.

Como resultado da avaliação preguiçosa, você não precisa de nenhum mecanismo especial para limitar os resultados da consulta com o Realm. Por exemplo, se a sua consulta corresponder a milhares de objetos, mas você quiser carregar somente os dez primeiros, basta acessar somente os dez primeiros elementos da collection de resultados.

Graças à avaliação preguiçosa, a tarefa comum da paginação se torna bastante simples. Por exemplo, suponha que você tenha uma coleção de resultados associada a uma consulta que corresponda a milhares de objetos em seu domínio. Você exibe cem objetos por página. Para avançar para qualquer página, basta acessar os elementos da coleta de resultados começando pelo índice que corresponde à página de destino.

Os exemplos nesta página usam os seguintes 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 {
@Persisted var id: ObjectId
@Persisted var name = ""
}
class Dog: Object {
@Persisted var name = ""
@Persisted var age = 0
@Persisted var color = ""
@Persisted var currentCity = ""
@Persisted var citiesVisited: MutableSet<String>
@Persisted var companion: AnyRealmValue
// To-one relationship
@Persisted var favoriteToy: DogToy?
// Map of city name -> favorite park in that city
@Persisted 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 {
@Persisted(primaryKey: true) var id = 0
@Persisted var name = ""
// To-many relationship - a person can have many dogs
@Persisted var dogs: List<Dog>
// Inverse relationship - a person can be a member of many clubs
@Persisted(originProperty: "members") var clubs: LinkingObjects<DogClub>
// Embed a single object.
// Embedded object properties must be marked optional.
@Persisted var address: Address?
convenience init(name: String, address: Address) {
self.init()
self.name = name
self.address = address
}
}
class DogClub: Object {
@Persisted var name = ""
@Persisted var members: List<Person>
// DogClub has an array of regional office addresses.
// These are embedded objects.
@Persisted var regionalOfficeAddresses: List<Address>
convenience init(name: String, addresses: [Address]) {
self.init()
self.name = name
self.regionalOfficeAddresses.append(objectsIn: addresses)
}
}
class Address: EmbeddedObject {
@Persisted var street: String?
@Persisted var city: String?
@Persisted var country: String?
@Persisted var postalCode: String?
}

Se você souber a chave primária de um determinado objeto, poderá procurá-la diretamente com +[RLMObject objectForPrimaryKey:].

// Get a specific person from the default realm
Person *specificPerson = [Person objectForPrimaryKey:@12345];

Se você souber qual é a chave primária de um determinado objeto, poderá buscá-la diretamente com Realm.object(ofType:forPrimaryKey:).

let realm = try! Realm()
let specificPerson = realm.object(ofType: Person.self, forPrimaryKey: 12345)

Para executar query de objetos de um determinado tipo em um Realm, passe a instância do Realm para +[ YourRealmObjectClass allObjectsInRealm:]. Substitua YourRealmObjectClass pelo nome da classe de Objeto de Realm . Esse comando retorna um objeto RLMResults que representa todos os objetos de um determinado tipo no Realm.

RLMRealm *realm = [RLMRealm defaultRealm];
RLMResults *dogs = [Dog allObjectsInRealm:realm];
RLMResults *people = [Person allObjectsInRealm:realm];

Para buscar objetos de um determinado tipo em um domínio, passe a instância do metatipo YourClassName.self para Realm.objects(_:). Esse comando retorna um objeto Results que representa todos os objetos de um determinado tipo no domínio.

let realm = try! Realm()
// Access all dogs in the realm
let dogs = realm.objects(Dog.self)

Um filtro seleciona um subconjunto de resultados com base no(s) valor(es) de uma ou mais propriedades do objeto. O Realm oferece um mecanismo de consulta completo que você pode usar para definir filtros.

Novidades na versão 10,19,0.

Para usar a API de consulta do Realm Swift, chame .where com um fechamento que contenha uma expressão query 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, chame Results.filter(_:) com um predicado de query.

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, chame -[RLMResults objectswhere:] com um predicado de query.

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"];

Dica

Filtrar nas Propriedades de Objetos Relacionados e Embarcados

Para filtrar uma consulta com base na propriedade de um objeto incorporado ou de um objeto relacionado, use a notação de pontos como se estivesse em um objeto normal aninhado.

Os tipos no seu predicado devem corresponder aos tipos das propriedades. Evite comparar propriedades de ObjectID com strings, pois o Realm não converte automaticamente strings em ObjectIDs.

Novidades na versão 10,19,0.

A segurança do tipo integrado da Realm Swift Query API simplifica a escrita de uma consulta com um 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")
}

O exemplo a seguir mostra a maneira correta e incorreta de escrever uma query com um ObjectId dado o seguinte 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

Você pode fazer consultas por meio de um relacionamento da mesma forma que acessaria um nó de um objeto regular do Swift ou Objective-C.

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)")

Você pode fazer consultas por meio de um relacionamento inverso da mesma forma que acessaria um nó de um objeto regular do Swift ou Objective-C.

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)")

Use a notação de ponto para filtrar ou classificar uma coleção de objetos com base em um valor de propriedade de objeto incorporado:

Observação

Não é possível consultar objetos incorporados diretamente. Em vez disso, acesse objetos incorporados por meio de uma consulta para o tipo de objeto pai.

Novidades na versão 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);

Você pode iterar e verificar os valores de um mapa Realm como faria com um Dicionário:

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)")
}
}

Você pode consultar um MutableSet para verificar se ele contém um elemento. Se você estiver trabalhando com vários conjuntos, poderá verificar a interseção de dois conjuntos ou verificar se um conjunto é um subconjunto do outro.

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"

Ao ler uma propriedade AnyRealmValue, verifique o tipo do valor antes de fazer qualquer coisa com ele. O Realm Swift SDK fornece um enumeração AnyRealmValue que itera por todos os tipos que o AnyRealmValue pode armazenar.

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.")
}
}

Você pode comparar esses tipos de valores mistos:

  • Numérico: int, bool, float, double, decimal

  • Baseado em bytes: string, binário

  • Baseado em tempo: carimbo de data/hora, objectId

Ao usar o tipo de dados misto AnyRealmValue, lembre-se do seguinte:

  • equals consultas fazem a correspondência de valor e tipo

  • not equals consultas fazem a correspondência de objetos com valores ou tipos diferentes

  • domínio converte propriedades numéricas comparáveis sempre que possível. Por exemplo, em um campo de tipo misto, 1 corresponde a todos 1.0, 1 e verdadeiro.

  • As propriedades de string não correspondem a consultas numéricas. Por exemplo, em um campo de tipo misto, 1 não corresponde a "1". "1" não corresponde a 1, 1.0 ou verdadeiro.

Novidades na versão 10.47.0.

O Swift SDK fornece diversas formas para simplificar a query de dados geospaciais. Você pode usar as formas GeoCircle, GeoBox e GeoPolygon para definir os limites de suas queries de dados geoespaciais.

O SDK fornece dois tipos de dados especializados não persistentes para definir formas:

  • GeoPoint: uma estrutura que representa as coordenadas de uma ponta formada por um par de doubles contendo estes valores:

    • Latitude: varia entre -90 e 90 graus, inclusivo.

    • Longitude: varia entre -180 e 180 graus, inclusivo.

  • RLMDistance: uma estrutura auxiliar para representar e converter uma distância.

Um GeoCircle é uma forma circular cujos limites têm como origem um GeoPoint central e tem um tamanho correspondente a um raio medido em radianos. Você pode usar o tipo de dados conveniente RLMDistance do SDK para trabalhar com raios em unidades diferentes.

RLMDistance permite especificar a distância de raio para as suas formas geográficas em uma das quatro unidades:

  • .degrees

  • .kilometers

  • .miles

  • .radians

Opcionalmente, você pode usar os métodos de conveniência fornecidos para converter uma medida em outras unidades de distância.

// 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)!)
Dois círculos geográficos
clique para ampliar

Um GeoBox é uma forma retângulo cujos limites são determinados por coordenadas para um canto inferior esquerdo e um canto superior direito.

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!)
2 GeoBoxes
clique para ampliar

Um GeoPolygon é uma forma de polígono cujos limites consistem em um anel externo e 0 ou mais orifícios internos a serem excluídos da query geoespacial.

O anel externo de um polígono deve conter pelo menos três segmentos. O último e o primeiro GeoPoint devem ser iguais, o que indica um polígono fechado. Isto significa que são necessários pelo menos quatro GeoPoint valores para construir um polígono.

Os orifícios internos em um GeoPolygon devem estar inteiramente contidos no anel externo.

Os furos têm as seguintes restrições:

  • Os orifícios podem não se cruzar. O limite de um orifício não pode cruzar o interno e o externo de qualquer outro orifício.

  • Os furos podem não compartilhar bordas. Se um orifício contém uma aresta BI, nenhum outro orifício pode contê-la.

  • Os furos podem compartilhar vértices. No entanto, nenhum vértice pode aparecer duas vezes em um único orifício.

  • Nenhum vazio pode estar vazio.

  • Apenas um aninhamento é permitido.

// 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])
3 GeoPolygons
clique para ampliar

Você pode usar estas formas em uma query geoespacial. Você pode executar uma query de dados geoespaciais de três maneiras:

  • Usar o operador .geoWithin() com a API Realm Swift Query com segurança de tipo

  • Usar um .filter() com RQL

  • Usar um .filter() com uma query NSPredicate

Os exemplos abaixo mostram os resultados das queries usando estes dois objetos Company:

let company1 = Geospatial_Company()
company1.location = CustomGeoPoint(47.68, -122.35)
let company2 = Geospatial_Company(CustomGeoPoint(47.9, -121.85))
2 GeoPoints
clique para ampliar
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)")
Consultando um exemplo do GeoCircle.
clique para ampliar
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)")
Consultando um exemplo do GeoBox.
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)")
Consultando um exemplo do GeoPolygon.
clique para ampliar

Quando você usa a projeção de tipo para mapear tipos sem suporte para tipos com suporte, o acesso a essas propriedades geralmente é baseado no tipo persistente.

Ao trabalhar com tipos projetados, as consultas operam no tipo persistente. No entanto, você pode usar os tipos mapeados de forma intercambiável com os tipos persistentes em argumentos na maioria dos casos. A exceção são consultas em objetos incorporados.

Dica

Os tipos projetados suportam classificação e agregados onde o tipo persistente os suporta.

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")

Você pode consultar tipos embarcados nos tipos de propriedade permitidos dentro do objeto utilizando a igualdade de todos os nós.

As propriedades do link de objeto suportam comparações de igualdade, mas não oferecem suporte a comparações entre nós. Você pode consultar objetos incorporados para obter igualdade de nós em todos os tipos primitivos. Você não pode realizar comparações entre nós em objetos e coleções.

Como o esquema não tem nenhum conceito de mapeamentos de tipos personalizados, a leitura de dados por meio de qualquer uma das APIs dinâmicas fornece o tipo persistente subjacente. O Realm oferece suporte à gravação de tipos mapeados por meio de uma API dinâmica e converte o tipo projetado em tipo persistente.

O uso mais comum das APIs dinâmicas é a migração. Você pode escrever tipos projetados durante a migração, e o Realm converte o tipo projetado no tipo persistente. No entanto, a leitura de dados durante uma migração fornece o tipo persistente subjacente.

Quando usar um realm isolado por atores, você pode usar as funcionalidades de simultaneidade do Swift para consultar objetos de forma assíncrona.

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")

Se você precisar avançar manualmente o estado de um realm observado na thread principal ou de um realm isolado por ator, chame await realm.asyncRefresh(). Isso atualiza o realm e os objetos pendentes gerenciados pelo Realm para apontar para os dados mais recentes e fornecer quaisquer notificações aplicáveis.

Para obter mais informações sobre como trabalhar com o domínio usando os recursos de simultaneidade do Swift, consulte Use Realm with Actors - Swift SDK.

Uma operação de classificação permite que você configure a ordem em que o Realm Database retorna os objetos consultados. Você pode classificar com base em uma ou mais propriedades dos objetos na coleção de resultados. O Realm só garante uma ordem consistente de resultados se você classificá-los explicitamente.

Para classificar, chame -[RLMResults sortedResultsUsingKeyPath:ascending:] com o caminho da chave desejado para a classificação.

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];

Novidade na versão 10.11.0.

Você pode classificar com o keyPath seguro ao chamar Results.sorted(by: ) com o nome do keyPath e a ordem de classificação 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 classificar usando a API mais antiga, chame Results.sorted(byKeyPath:ascending:) com o caminho da chave desejado para a classificação.

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")

Dica

Classificar nas Propriedades de Objetos Relacionados e Embarcados

Para classificar uma consulta com base em uma propriedade de um objeto incorporado ou de um objeto relacionado, use não anotação como se estivesse em um objeto aninhado regular.

Observação

Somente é permitido classificar strings e consultas sem diferenciação de maiúsculas e minúsculas para conjuntos de caracteres em 'Latin Basic', 'Latin Supplement', 'Latin Extended A' e 'Latin Extended B' (UTF-8 faixa 0-591).

Você pode dividir os resultados em seções individuais. Cada seção corresponde a uma chave gerada a partir de uma propriedade no objeto que representa.

Por exemplo, você pode adicionar uma variável computada ao seu objeto para ter a primeira letra da propriedade name:

// Computed variable that is not persisted, but only
// used to section query results.
var firstLetter: String {
return name.first.map(String.init(_:)) ?? ""
}

Em seguida, você pode criar uma coleção segura de tipo SectionedResults para esse objeto e usá-la para recuperar objetos seccionados por essa variável computada:

var dogsByFirstLetter: SectionedResults<String, Dog>
dogsByFirstLetter = realm.objects(Dog.self).sectioned(by: \.firstLetter, ascending: true)

Você pode obter uma contagem das seções, obter uma lista de chaves ou acessar uma 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)

Você também pode seccionar usando um retorno de chamada de resposta. Isso permite seccionar uma coleção de primitivos ou ter mais controle sobre como a chave de seção é gerada.

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

Você pode observar instâncias do SectionedResults e ResultsSection e ambos estão em conformidade com ThreadConfined.

Você pode usar os operadores de agregação do Realm para consultas sofisticadas em relação às propriedades da lista.

Novidades na versão 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"];

Como os resultados são avaliados preguiçosamente, você pode agrupar várias consultas. Diferentemente dos bancos de dados tradicionais, isso não exige uma viagem separada ao banco de dados para cada consulta sucessiva.

Exemplo

Para obter um conjunto de resultados para cães amarelos e cães amarelos cujos nomes começam com 'B', encadeie duas consultas dessa forma:

Novidades na versão 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'"];

Para consultar as projeções de classe em um domínio, passe a instância do meta-tipo YourProjectionName.self para Realm.objects(_:). Isso retorna um objeto Results que representa todos os objetos de projeção de classe no domínio.

// 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)

Dica

Não faça consultas derivadas sobre os resultados da projeção da classe. Em vez disso, execute uma consulta com o objeto Realm diretamente e, em seguida, projete o resultado. Se você tentar fazer uma consulta derivada no topo dos resultados de projeção da classe, consultar um campo com o mesmo nome e tipo que o objeto original funciona, mas consultar um campo com um nome ou tipo que não está no objeto original falha.