Overview
Para filtrar datos en su ámbito, puede aprovechar el motor de consulta de Realm.
Novedades de la versión 10.19.0: API de consulta Swift de Realm
La La API de consulta de Realm Swift ofrece a los desarrolladores de Swift una forma idiomática de consultar datos. Utilice la sintaxis de estilo Swift para consultar un realm con las ventajas del autocompletado y la seguridad de tipos. La API de consulta de Realm Swift no reemplaza a la API de consulta NSPredicate en las versiones más recientes del SDK; puede usar cualquiera de las dos.
Para versiones del SDK anteriores a la 10.19.0, o para desarrolladores de Objective-C, el motor de query de Realm admite query de NSPredicate.
About the Examples on This Page
Los ejemplos de esta página utilizan un conjunto de datos simple para una aplicación de lista de tareas. Los dos tipos de objetos Realm son Project
y Task. Un Task tiene un nombre, el nombre del asignado y un indicador de finalización. También hay un número arbitrario para la prioridad (cuanto más alto, más importante) y un recuento de minutos dedicados a trabajar en él. Finalmente, un Task puede tener una o más cadenas labels y uno o más enteros ratings.
Un Project tiene cero o más Tasks.
See the schema for these two classes, Project and Task, below:
// Task.h @interface Task : RLMObject @property NSString *name; @property bool isComplete; @property NSString *assignee; @property int priority; @property int progressMinutes; @end RLM_COLLECTION_TYPE(Task) // Task.m @implementation Task @end // Project.h @interface Project : RLMObject @property NSString *name; @property RLMArray<Task> *tasks; @end // Project.m @implementation Project @end
class Task: Object { var name = "" var isComplete = false var assignee: String? var priority = 0 var progressMinutes = 0 var labels: MutableSet<String> var ratings: MutableSet<Int> } class Project: Object { var name = "" var tasks: List<Task> }
You can set up the realm for these examples with the following code:
RLMRealm *realm = [RLMRealm defaultRealm]; [realm transactionWithBlock:^() { // Add projects and tasks here }]; RLMResults *tasks = [Task allObjectsInRealm:realm]; RLMResults *projects = [Project allObjectsInRealm:realm];
let realm = try! Realm() try! realm.write { // Add tasks and projects here. let project = Project() project.name = "New Project" let task = Task() task.assignee = "Alex" task.priority = 5 project.tasks.append(task) realm.add(project) // ... } let tasks = realm.objects(Task.self) let projects = realm.objects(Project.self)
Realm Swift Query API
New in version 10.19.0: For SDK versions older than 10.19.0, use the NSPredicate query API.
You can build a filter with Swift-style syntax using the .where Realm Swift query API:
let realmSwiftQuery = projects.where { ($0.tasks.progressMinutes > 1) && ($0.tasks.assignee == "Ali") }
Esta API de query construye un NSPredicate para realizar la query. Ofrece a los desarrolladores una API tipada, idiomática y segura que pueden usar directamente, y abstrae la construcción de NSPredicate.
La API .where recibe una devolución de llamada que evalúa como verdadera o falsa. Esta devolución de llamada recibe una instancia del tipo consultado, y se puede usar el compilador para comprobar estáticamente que se están creando consultas válidas que hacen referencia a propiedades válidas.
In the examples on this page, we use the $0 shorthand to reference the variable passed into the callback.
Operadores
Hay varios tipos de operadores disponibles para consultar una colección de Realm. Las queries funcionan evaluando una expresión de operador para cada objeto en la colección consultada. Si la expresión se resuelve en true, Realm base de datos incluye el objeto en la colección de resultados.
Operadores de comparación
You can use Swift comparison operators with the Realm Swift Query API (==, !=, >, >=, <, <=).
Ejemplo
The following example uses the query engine's comparison operators to:
Encuentre tareas de alta prioridad comparando el valor de la propiedad
prioritycon un número umbral, por encima del cual la prioridad puede considerarse alta.Find long-running tasks by seeing if the
progressMinutesproperty is at or above a certain value.Find unassigned tasks by finding tasks where the
assigneeproperty is equal tonull.
let highPriorityTasks = tasks.where { $0.priority > 5 } print("High-priority tasks: \(highPriorityTasks.count)") let longRunningTasks = tasks.where { $0.progressMinutes >= 120 } print("Long running tasks: \(longRunningTasks.count)") let unassignedTasks = tasks.where { $0.assignee == nil } print("Unassigned tasks: \(unassignedTasks.count)")
Colecciones
Puedes consultar valores dentro de una colección usando los operadores .contains. Puedes buscar valores individuales por elemento o dentro de un rango.
Operador | Descripción |
|---|---|
.in(_ collection:) | Se evalúa como |
.contains(_ element:) | Equivalente al operador |
| Equivalent to the |
| Equivalent to the |
Ejemplo
Buscar tareas donde la propiedad MutableSet de la colección "
labels" contenga "quick win".Encuentra tareas donde la propiedad
progressMinutesse encuentre en un rango determinado de minutos.
let quickWinTasks = tasks.where { $0.labels.contains("quick win") } print("Tasks labeled 'quick win': \(quickWinTasks.count)") let progressBetween30and60 = tasks.where { $0.progressMinutes.contains(30...60) } print("Tasks with progress between 30 and 60 minutes: \(progressBetween30and60.count)")
Busque tareas donde la propiedad de colección MutableSet labels contenga cualquiera de los elementos en la matriz dada: "quick win" o "bug".
let quickWinOrBugTasks = tasks.where { $0.labels.containsAny(in: ["quick win", "bug"]) } print("Tasks labeled 'quick win' or 'bug': \(quickWinOrBugTasks.count)")
New in version 10.23.0:: The IN operator
La API de consulta de Realm Swift ahora admite el operador IN. Se evalúa como true si la propiedad referenciada por la expresión contiene el valor.
Ejemplo
Find tasks assigned to specific teammates Ali or Jamie by seeing if the assignee property is in a list of names.
let taskAssigneeInAliOrJamie = tasks.where { let assigneeNames = ["Ali", "Jamie"] return $0.assignee.in(assigneeNames) } print("Tasks IN Ali or Jamie: \(taskAssigneeInAliOrJamie.count)")
Operadores lógicos
You can make compound queries using Swift logical operators (&&, !, ||).
Ejemplo
We can use the query language's logical operators to find all of Ali's completed tasks. That is, we find all tasks where the assignee property value is equal to 'Ali' AND the isComplete property value is true:
let aliComplete = tasks.where { ($0.assignee == "Ali") && ($0.isComplete == true) } print("Ali's complete tasks: \(aliComplete.count)")
Operadores de String
You can compare string values using these string operators. Regex-like wildcards allow more flexibility in search.
Nota
You can use the following options with string operators:
.caseInsensitivefor case insensitivity.$0.name.contains("f", options: .caseInsensitive) .diacriticInsensitivefor diacritic insensitivity: Realm treats special characters as the base character (e.g.é->e).$0.name.contains("e", options: .diacriticInsensitive)
Operador | Descripción |
|---|---|
.starts(with value: String) | Se evalúa como |
.contains(_ value: String) | Evalúa como |
.ends(with value: String) | Evaluates to |
.like(_ value: String) | Evaluates to
For example, the wildcard string "d?g" matches "dog", "dig", and "dug", but not "ding", "dg", or "a dog". |
== | Evaluates to |
!= | Se evalúa como |
Ejemplo
The following example uses the query engine's string operators to find:
Projects with a name starting with the letter 'e'
Projects with names that contain 'ie'
Projects with an
assigneeproperty whose value is similar toAl?xProjects that contain e-like characters with diacritic insensitivity
// Use the .caseInsensitive option for case-insensitivity. let startWithE = projects.where { $0.name.starts(with: "e", options: .caseInsensitive) } print("Projects that start with 'e': \(startWithE.count)") let containIe = projects.where { $0.name.contains("ie") } print("Projects that contain 'ie': \(containIe.count)") let likeWildcard = tasks.where { $0.assignee.like("Al?x") } print("Tasks with assignees like Al?x: \(likeWildcard.count)") // Use the .diacreticInsensitive option for diacritic insensitivty: contains 'e', 'E', 'é', etc. let containElike = projects.where { $0.name.contains("e", options: .diacriticInsensitive) } print("Projects that contain 'e', 'E', 'é', etc.: \(containElike.count)")
Nota
String sorting and case-insensitive queries are only supported for character sets in 'Latin Basic', 'Latin Supplement', 'Latin Extended A', and 'Latin Extended B' (UTF-8 range 0-591).
Operadores geoespaciales
New in version 10.47.0.
Use the geoWithin operator to query geospatial data with one of the SDK's provided shapes:
GeoCircleGeoBoxGeoPolygon
This operator evaluates to true if:
An object has a geospatial data "shape" containing a
Stringproperty with the value of Point and aListcontaining a longitude/latitude pair.The longitude/latitude of the persisted object falls within the geospatial query shape.
let companiesInSmallCircle = realm.objects(Geospatial_Company.self).where { $0.location.geoWithin(smallCircle!) } print("Number of companies in small circle: \(companiesInSmallCircle.count)")
Para obtener más información sobre cómo consultar datos geoespaciales, consulte Consultar datos geoespaciales.
Aggregate Operators
Se puede aplicar un operador de agregación a una propiedad de colección de un objeto Realm. Los operadores de agregación recorren una colección y la reducen a un único valor.
Operador | Descripción |
|---|---|
.avg | Se evalúa como el valor promedio de una propiedad numérica dada en una colección. |
.count | Evaluates to the number of objects in the given collection. This is currently only supported on to-many relationship collections and not on lists of primitives. In order to use |
.max | Evaluates to the highest value of a given numerical property across a collection. |
.min | Evaluates to the lowest value of a given numerical property across a collection. |
.sum | Evaluates to the sum of a given numerical property across a collection. |
Ejemplo
We create a couple of filters to show different facets of the data:
Projects with average tasks priority above 5.
Projects that contain only low-priority tasks below 5.
Projects where all tasks are high-priority above 5.
Proyectos que contienen más de 5 tareas.
Long running projects.
let averageTaskPriorityAbove5 = projects.where { $0.tasks.priority.avg > 5 } print("Projects with average task priority above 5: \(averageTaskPriorityAbove5.count)") let allTasksLowerPriority = projects.where { $0.tasks.priority.max < 5 } print("Projects where all tasks are lower priority: \(allTasksLowerPriority.count)") let allTasksHighPriority = projects.where { $0.tasks.priority.min > 5 } print("Projects where all tasks are high priority: \(allTasksHighPriority.count)") let moreThan5Tasks = projects.where { $0.tasks.count > 5 } print("Projects with more than 5 tasks: \(moreThan5Tasks.count)") let longRunningProjects = projects.where { $0.tasks.progressMinutes.sum > 100 } print("Long running projects: \(longRunningProjects.count)")
Operadores de conjuntos
A set operator uses specific rules to determine whether to pass each input collection object to the output collection by applying a given query expression to every element of a given list property of the object.
Ejemplo
Running the following queries in projects collections returns:
Proyectos donde un conjunto de strings
labelscontiene cualquier término de "quick win", "bug".Projects where any element in a set of integer
ratingsis greater than 3.
let projectsWithGivenLabels = projects.where { $0.tasks.labels.containsAny(in: ["quick win", "bug"]) } print("Projects with quick wins: \(projectsWithGivenLabels.count)") let projectsWithRatingsOver3 = projects.where { $0.tasks.ratings > 3 } print("Projects with any ratings over 3: \(projectsWithRatingsOver3.count)")
Subqueries
Puede iterar a través de una propiedad de colección con otra consulta mediante una subconsulta. Para formar una subconsulta, debe encerrar la expresión entre paréntesis e inmediatamente después el agregador .count.
(<query>).count > n
If the expression does not produce a valid subquery, you'll get an exception at runtime.
Ejemplo
Ejecutar la siguiente query en una colección projects devuelve proyectos con tareas que no han sido completadas por un usuario llamado Alex.
let subquery = projects.where { ($0.tasks.isComplete == false && $0.tasks.assignee == "Alex").count > 0 } print("Projects with incomplete tasks assigned to Alex: \(subquery.count)")
Consultas NSPredicate
You can build a filter with NSPredicate:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"progressMinutes > %@ AND name == %@", @1, @"Ali"];
let predicate = NSPredicate(format: "progressMinutes > 1 AND name == %@", "Ali")
Expresiones
Los filtros consisten en expresiones en un NSPredicate. Una expresión consta de uno de los siguientes:
The name (keypath) of a property of the object currently being evaluated.
An operator and up to two argument expression(s).
A value, such as a string (
'hello') or a number (5).
Notación de puntos
Al referirse a una propiedad de un objeto, se puede usar la notación de puntos para referirse a sus propiedades secundarias. Incluso se puede usar la notación de puntos para referirse a las propiedades de objetos incrustados y relaciones.
For example, consider a query on an object with a workplace property that refers to a Workplace object. The Workplace object has an embedded object property, address. You can chain dot notations to refer to the zipcode property of that address:
workplace.address.zipcode == 10012
Substitutions
Puedes utilizar las siguientes sustituciones en tus cadenas de formato de predicado:
%@to specify values%Kpara especificar rutas de acceso clave
[NSPredicate predicateWithFormat:@"%K > %@ AND %K == %@", @"progressMinutes", @1, @"name", @"Ali"];
NSPredicate(format: "%K > %@ AND %K == %@", "progressMinutes", NSNumber(1), "name", "Ali")
Operadores
Hay varios tipos de operadores disponibles para filtrar una colección de Realm. Los filtros funcionan evaluando una expresión de operador para cada objeto de la colección que se filtra. Si la expresión se resuelve como true, Realm Database incluye el objeto en la colección de resultados.
Operadores de comparación
The most straightforward operation in a search is to compare values.
Importante
Types Must Match
El tipo en ambos lados del operador debe ser equivalente. Por ejemplo, comparar un ObjectId con string resultará en una falla de precondición con un mensaje similar a:
"Expected object of type object id for property 'id' on object of type 'User', but received: 11223344556677889900aabb (Invalid value)"
You can compare any numeric type with any other numeric type.
Operador | Descripción |
|---|---|
| Evaluates to |
==, = | Evaluates to |
> | Evaluates to |
>= | Evaluates to |
| Evaluates to |
< | Devuelve |
<= | Se evalúa como |
!=, <> | Evaluates to |
Ejemplo
The following example uses the query engine's comparison operators to:
Encuentre tareas de alta prioridad comparando el valor de la propiedad
prioritycon un número umbral, por encima del cual la prioridad puede considerarse alta.Find long-running tasks by seeing if the
progressMinutesproperty is at or above a certain value.Find unassigned tasks by finding tasks where the
assigneeproperty is equal tonull.Find tasks assigned to specific teammates Ali or Jamie by seeing if the
assigneeproperty is in a list of names.
NSLog(@"High priority tasks: %lu", [[tasks objectsWithPredicate:[NSPredicate predicateWithFormat:@"priority > %@", @5]] count]); NSLog(@"Short running tasks: %lu", [[tasks objectsWhere:@"progressMinutes between {1, 15}"] count]); NSLog(@"Unassigned tasks: %lu", [[tasks objectsWhere:@"assignee == nil"] count]); NSLog(@"Ali or Jamie's tasks: %lu", [[tasks objectsWhere:@"assignee IN {'Ali', 'Jamie'}"] count]); NSLog(@"Tasks with progress between 30 and 60 minutes: %lu", [[tasks objectsWhere:@"progressMinutes BETWEEN {30, 60}"] count]);
let highPriorityTasks = tasks.filter("priority > 5") print("High priority tasks: \(highPriorityTasks.count)") let longRunningTasks = tasks.filter("progressMinutes > 120") print("Long running tasks: \(longRunningTasks.count)") let unassignedTasks = tasks.filter("assignee == nil") print("Unassigned tasks: \(unassignedTasks.count)") let aliOrJamiesTasks = tasks.filter("assignee IN {'Ali', 'Jamie'}") print("Ali or Jamie's tasks: \(aliOrJamiesTasks.count)") let progressBetween30and60 = tasks.filter("progressMinutes BETWEEN {30, 60}") print("Tasks with progress between 30 and 60 minutes: \(progressBetween30and60.count)")
Operadores lógicos
You can make compound predicates using logical operators.
Operador | Descripción |
|---|---|
and&& | Se evalúa como |
not! | Negates the result of the given expression. |
or|| | Evaluates to |
Ejemplo
We can use the query language's logical operators to find all of Ali's completed tasks. That is, we find all tasks where the assignee property value is equal to 'Ali' AND the isComplete property value is true:
NSLog(@"Ali's complete tasks: %lu", [[tasks objectsWhere:@"assignee == 'Ali' AND isComplete == true"] count]);
let aliComplete = tasks.filter("assignee == 'Ali' AND isComplete == true") print("Ali's complete tasks: \(aliComplete.count)")
Operadores de String
You can compare string values using these string operators. Regex-like wildcards allow more flexibility in search.
Nota
Puede utilizar los siguientes modificadores con los operadores de cadena:
[c]for case insensitivity.[NSPredicate predicateWithFormat: @"name CONTAINS[c] 'f'"] NSPredicate(format: "name CONTAINS[c] 'f'") [d]for diacritic insensitivity: Realm treats special characters as the base character (e.g.é->e).[NSPredicate predicateWithFormat: @"name CONTAINS[d] 'e'"] NSPredicate(format: "name CONTAINS[d] 'e'")
Operador | Descripción |
|---|---|
beginsWith | Evaluates to |
contains, in | Evalúa como |
endsWith | Evaluates to |
like | Evaluates to
For example, the wildcard string "d?g" matches "dog", "dig", and "dug", but not "ding", "dg", or "a dog". |
==, = | Evaluates to |
!=, <> | Se evalúa como |
Ejemplo
We use the query engine's string operators to find projects with a name starting with the letter 'e' and projects with names that contain 'ie':
// Use [c] for case-insensitivity. NSLog(@"Projects that start with 'e': %lu", [[projects objectsWhere:@"name BEGINSWITH[c] 'e'"] count]); NSLog(@"Projects that contain 'ie': %lu", [[projects objectsWhere:@"name CONTAINS 'ie'"] count]);
// Use [c] for case-insensitivity. let startWithE = projects.filter("name BEGINSWITH[c] 'e'") print("Projects that start with 'e': \(startWithE.count)") let containIe = projects.filter("name CONTAINS 'ie'") print("Projects that contain 'ie': \(containIe.count)") // [d] for diacritic insensitivty: contains 'e', 'E', 'é', etc. let containElike = projects.filter("name CONTAINS[cd] 'e'") print("Projects that contain 'e', 'E', 'é', etc.: \(containElike.count)")
Nota
String sorting and case-insensitive queries are only supported for character sets in 'Latin Basic', 'Latin Supplement', 'Latin Extended A', and 'Latin Extended B' (UTF-8 range 0-591).
Operadores geoespaciales
New in version 10.47.0.
You can perform a geospatial query using the IN operator with one of the SDK's provided shapes:
GeoCircleGeoBoxGeoPolygon
This operator evaluates to true if:
An object has a geospatial data "shape" containing a
Stringproperty with the value of Point and aListcontaining a longitude/latitude pair.The longitude/latitude of the persisted object falls within the geospatial query shape.
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)")
Para obtener más información sobre cómo consultar datos geoespaciales, consulte Consultar datos geoespaciales.
Aggregate Operators
Se puede aplicar un operador de agregación a una propiedad de colección de un objeto Realm. Los operadores de agregación recorren una colección y la reducen a un único valor.
Operador | Descripción |
|---|---|
@avg | Se evalúa como el valor promedio de una propiedad numérica dada en una colección. |
@count | Evaluates to the number of objects in the given collection. This is currently only supported on to-many relationship collections and not on lists of primitives. In order to use |
@max | Evaluates to the highest value of a given numerical property across a collection. |
@min | Evaluates to the lowest value of a given numerical property across a collection. |
@sum | Evaluates to the sum of a given numerical property across a collection. |
Ejemplo
We create a couple of filters to show different facets of the data:
Projects with average tasks priority above 5.
Long running projects.
NSLog(@"Projects with average tasks priority above 5: %lu", [[projects objectsWhere:@"tasks.@avg.priority > 5"] count]); NSLog(@"Projects where all tasks are lower priority: %lu", [[projects objectsWhere:@"tasks.@max.priority < 5"] count]); NSLog(@"Projects where all tasks are high priority: %lu", [[projects objectsWhere:@"tasks.@min.priority > 5"] count]); NSLog(@"Projects with more than 5 tasks: %lu", [[projects objectsWhere:@"tasks.@count > 5"] count]); NSLog(@"Long running projects: %lu", [[projects objectsWhere:@"tasks.@sum.progressMinutes > 100"] count]);
let averageTaskPriorityAbove5 = projects.filter("tasks.@avg.priority > 5") print("Projects with average task priority above 5: \(averageTaskPriorityAbove5.count)") let allTasksLowerPriority = projects.filter("tasks.@max.priority < 5") print("Projects where all tasks are lower priority: \(allTasksLowerPriority.count)") let allTasksHighPriority = projects.filter("tasks.@min.priority > 5") print("Projects where all tasks are high priority: \(allTasksHighPriority.count)") let moreThan5Tasks = projects.filter("tasks.@count > 5") print("Projects with more than 5 tasks: \(moreThan5Tasks.count)") let longRunningProjects = projects.filter("tasks.@sum.progressMinutes > 100") print("Long running projects: \(longRunningProjects.count)")
Operadores de conjuntos
A set operator uses specific rules to determine whether to pass each input collection object to the output collection by applying a given predicate to every element of a given list property of the object.
Operador | Descripción |
|---|---|
| Devuelve objetos donde el predicado evalúa como |
| Devuelve objetos donde el predicado evalúa a |
| Returns objects where the predicate evaluates to false for all objects in the collection. |
Ejemplo
Utilizamos los operadores de conjunto del motor de consulta para encontrar:
Projects with no complete tasks.
Proyectos con tareas de máxima prioridad.
NSLog(@"Projects with no complete tasks: %lu", [[projects objectsWhere:@"NONE tasks.isComplete == true"] count]); NSLog(@"Projects with any top priority tasks: %lu", [[projects objectsWhere:@"ANY tasks.priority == 10"] count]);
let noCompleteTasks = projects.filter("NONE tasks.isComplete == true") print("Projects with no complete tasks: \(noCompleteTasks.count)") let anyTopPriorityTasks = projects.filter("ANY tasks.priority == 10") print("Projects with any top priority tasks: \(anyTopPriorityTasks.count)")
Subqueries
You can iterate through a collection property with another query using the SUBQUERY() predicate function. SUBQUERY() has the following signature:
SUBQUERY(<collection>, <variableName>, <predicate>)
collection: the name of the list property to iterate throughvariableName: un nombre de variable del elemento actual a utilizar en la subconsultapredicate: a string that contains the subquery predicate. You can use the variable name specified byvariableNameto refer to the currently iterated element.
Ejemplo
Running the following filter on a projects collection returns projects with tasks that have not been completed by a user named Alex.
NSPredicate *predicate = [NSPredicate predicateWithFormat: @"SUBQUERY(tasks, $task, $task.isComplete == %@ AND $task.assignee == %@).@count > 0", @NO, @"Alex"]; NSLog(@"Projects with incomplete tasks assigned to Alex: %lu", [[projects objectsWithPredicate:predicate] count]);
let predicate = NSPredicate( format: "SUBQUERY(tasks, $task, $task.isComplete == false AND $task.assignee == %@).@count > 0", "Alex") print("Projects with incomplete tasks assigned to Alex: \(projects.filter(predicate).count)")