CKQuery object manages the criteria to apply when searching for records in a database. You create a query object as the first step in the search process. The query object stores the search parameters, including the type of records to search, the match criteria (predicate) to apply, and the sort parameters to apply to the results. The second step is to use the query object to initialize a
CKQuery object, which you then execute to generate the results.
- iOS 8.0+
- macOS 10.10+
- tvOS 8.0+
- watchOS 2.0+
Always designate a record type and predicate when you create a query object. The record type narrows the scope of the search to one type of record, and the predicate defines the conditions for which records of that type are considered a match. Predicates usually compare one or more fields of a record to constant values, but you can create predicates that return all records of a given type or perform more nuanced searches.
Because the record type and predicate cannot be changed later, you can use the same
CKQuery object to initialize multiple
CKQuery objects, each of which targets a different database or zone.
Building Your Predicates
NSPredicate object defines the logical conditions for determining whether a record is a match for a query. The
CKQuery class supports only a subset of the predicate behaviors offered by the full
Predicate Rules for Query Objects
The predicates you create for your query objects must follow these rules:
Predicates are based on a format string. You cannot use value or block-based predicates.
Predicates use only the operators listed in Table 2.
Predicates operate only on fields containing the following types of data:
Key names used in predicates correspond to fields in the currently evaluated record. Key names may include the names of the record’s metadata properties such as "
creation” or any data fields you added to the record. You cannot use key paths to specify fields in related records.
Predicates support the following variable substitution strings:
%@for value objects such as strings, numbers, and dates.
%Kfor the name of a field. This substitution variable indicates that the substituted string should be used to look up a field name.
With one exception, the
CONTAINSoperator can be used only to test list membership. The exception is when you use it to perform full-text searches in conjunction with the
selfkey path. The
selfkey path causes the server to look in searchable string-based fields for the specified token string. For example, a predicate string of
@"self contains 'blue'"searches for the word “blue” in all fields marked for inclusion in full-text searches. You cannot use the
selfkey path to search in fields whose type is not a string.
SOMEaggregate operators may be combined with the
CONTAINSoperators to perform list membership tests.
distanceoperator function performs a radius-based location comparison and that comparison must determine whether the location value is inside the circular area you provide. You cannot use it to search for locations outside of the specified circular area. Locations are indexed at a resolution of no less than 10 km.
To Location: from Location:
ALLaggregate operator is not supported.
NOTcompound operator is not supported in the following cases:
You cannot use it to negate an
You cannot use it in tokenized queries such as
self CONTAINS 'value'.
You cannot use it with the
To Location: from Location:
You cannot use it in
Supported Predicate Operators
Table 2 lists the operators you may use in predicates associated with a
Boolean value predicates
Basic compound predicates
Specifying an unsupported operator or data type in your query’s predicate results in an error when you execute the query. For more information about creating predicate objects, see Predicate Programming Guide.
Sample Predicate Format Strings
To match records that link to a different record whose ID you know, create a predicate that matches a field containing a reference object as shown in Listing 1. In the example, the
employee field of the record contains a
CKReference object that points to another record. When the query executes, a match occurs when the ID in the locally created
CKReference object is the same ID found in the specified field of the record.
To match the contents of a field to a specific value, use a predicate similar to the ones shown in Listing 2. All of the listed predicates generate the same set of results, which in the example means that the
favorite field contains the value
red. The value in the field must match the value you specify in the predicate exactly. String-based comparisons are case insensitive but otherwise all comparisons must be an exact match of the specified value.
You can match against more than one value at a time by using a predicate similar to the ones in Listing 3. In the example, the predicates report a match if the value in the
favorite field of a record matches either of the values
For fields that contain string values, you can match the beginning portion of the string using the
BEGINSWITH operator as shown in Listing 4. You cannot use other string comparison operators such as
ENDSWITH. When using this operator, the field must contain a string value and must start with the string you specified. Matches are case sensitive. In the examples, the predicate matches records whose
favorite field contained the strings
red green duct tape.
To perform a tokenized search of a record’s fields, use the special operator
self. A tokenized search searches any fields that have full-text search enabled, which is all string-based fields by default. Each distinct word in the tokenized string is treated as a separate token for the purpose of searching. Comparisons are case- and diacritic-insensitive. These token strings may be found in a single field or in multiple fields.
Listing 5 shows an example that searches the fields of a record for the token strings
To search for multiple tokens present in the fields, use the
AND predicate operator, as shown in Listing 6.
To test whether two locations are near each other, create a predicate using the
distance function as shown in Listing 7. Predicates that use this function must have the structure shown in the listing. In your code, replace the
location variable with a field name from one of your records. (This data type for the field must be a
CLLocation object.) Similarly, replace the
radius values with appropriate values from your app. The
fixed value is the geographic coordinate that marks the center of a circle with the specified radius. In this example, the predicate returns a match if the location in the record is within 10 kilometers of the specified latitude and longitude.
To retrieve all records of a given type, use the
TRUEPREDICATE expression as shown in Listing 8. A predicate with this operator always evaluates to true and thus matches every record. When using such an operator, it is recommended that you use a cursor to batch the results into smaller groups for processing.
Indexes and Full-Text Search
Indexes make it possible to search the contents of your records efficiently. During development, the server indexes all fields whose data types can be used in the predicate of a query. This automatic indexing makes it easier to experiment with queries during development, but these indexes take up space in a database and take time to generate and maintain. So when migrating to a production environment, remove the indexes for any fields that you do not actually use in queries.
Full-text search is another feature that is on by default for all fields during development. When you move to the production environment, disable full-text search for fields whose contents you do not need to search. As with removing indexes, disabling full-text search improves the performance of your tokenized searches. To configure the indexing and full-text search options for fields in your schema, use CloudKit Dashboard. For more information about disabling unused indexes, read Disable Unused Indexes in CloudKit Quick Start.
In a full-text search, the following words are ignored if they appear in the token strings:
Executing a Search Using Your Query Object
To execute a query based on your query object, do one of the following:
CKQueryobject using your query object. Run the operation directly or add it to an operation queue to perform the query and deliver the results.
in Zone With: completion Handler:)
CKDatabaseto execute the query. Process the results in your completion handler.
Queries always run asynchronously and deliver results to a completion handler that you provide.