NSPredicate Cheatsheet

Download PDF

supported by Realm

Format string summary

@"attributeName == %@"

object’s attributeName value is equal to value passed in

@"%K == %@"

pass a string variable to %K, it will be represented as a keypath, then check if it’s value is equal to value passed in

@"%name IN $NAME_LIST"

templated for predicate, checks if the value of key name is in $NAME_LIST. Uses predicateWithSubstitutionVariables

@"'name' IN $NAME_LIST"

checks if the constant value ‘name’ is in $NAME_LIST. Uses predicateWithSubstitutionVariables

[NSPredicate predicateWithFormat: @"title == %@", @"minecraft"]

Keypath collection queries

@avg

returns the average of the objects in the collection as an NSNumber

@count

returns the number of objects in a collection as an NSNumber

@min

returns the minimum value of the objects in the collection as an NSNumber

@max

returns the maximum value of the objects in the collection as an NSNumber

@sum

returns the sum of the objects in the collection based on the property

[NSPredicate predicateWithFormat: @"expenses.@avg.doubleValue < 200"]

Object, array, and set operators

@distinctUnionOfObjects

returns an array containing the distinct objects in the property specified by the key path to the right of the operator

@unionOfObjects

returns the same as @distinctUnionOfObects except it also includes duplicates

NSArray *payees = [transactions valueForKeyPath:@"@distinctUnionOfObjects.payee"]

@distinctUnionOfArrays

returns an array containing the distinct objects in the property specified by the key path to the right of the operator

@unionOfArrays

returns the same as @distinctUnionOfArrays except it also includes duplicates

These must be run on an array of arrays. For example if you had:

NSArray *arrayOfTransactions = [[Array of transactions], [Array of transactions]]

NSArray *payees = [arrayOfTransactions valueForKeyPath:@"@distinctUnionOfObjects.payee"]

@distinctUnionOfSets

returns an NSSet instance containing distinct objects in the property specified by the key path to the right of the operator. Expects an NSSet instance containing NSSet instances

Array operations

array[index]

specifies the element at the specified index in the array.

array[FIRST]

specifies the first element in the array.

array[LAST]

specifies the last element in the array.

array[SIZE]

specifies the size of the array.

Let’s say we have a person with many dogs. index should be replaced with a number which will return the dog that you want to check against. Here we’re checking if the first dog’s age is 5.

[NSPredicate predicateWithFormat: @"dogs[0].age = 5"]

Here we’re checking if a person has 3 dogs

[NSPredicate predicateWithFormat: @"dogs[SIZE] = 3"]

Basic comparisons

=,==

Left hand expression is equal to right hand expression

>=,=>

Left hand expression is greater than or equal to right hand expression

<=,=<

Left hand expression is less than or equal to right hand expression

>

Left hand expression is greater than right hand expression

<

Left hand expression is less than right hand expression

!=,<>

Left hand expression is not equal to right hand expression

IN

Left hand expression must appear in collection specified by right hand expression. i.e. name IN {‘Milk’, ‘Eggs’, ‘Bread’}

BETWEEN

Left hand expression is between or equal to right hand expression. i.e. 1 Between {0, 33}. If your left hand expression was 0 or 33 it would also make this true

[NSPredicate predicateWithFormat: @"expenses BETWEEN {200, 400}"]

Basic compound predicates

AND,&&

Logical AND

OR,||

Logical OR

NOT,!

Logical NOT

[NSPredicate predicateWithFormat: @"age == 40 AND price > 67"]

String comparison operators

BEGINSWITH

Left hand expression begins with the right hand expression

CONTAINS

Left hand expression contains the right hand expression

ENDSWITH

Left hand expression ends with the right hand expression

LIKE

Left hand expression equals the right hand expression: ? and * are allowed as wildcard characters, where ? matches 1 character and * matches 0 or more characters

MATCHES

Left hand expression equals the right hand expression using a regex - style comparison

[NSPredicate predicateWithFormat: @"name BEGINSWITH 'm'"]

Aggregate operators

ANY,SOME

returns objects where ANY or SOME of the predicate results are true.

ALL

returns objects where ALL of the predicate results are true.

NONE

returns objects where NONE of the predicate results are true.

[NSPredicate predicateWithFormat: @"ALL expenses > 1000"]

Subqueries

SUBQUERY(collection, variableName, predicateFormat)

Iterates through the collection to return qualifying queries

Collection - array or set of objects

variableName - variable that represents an iterated object

predicateFormat - predicate that runs using the variableName

[NSPredicate predicateWithFormat: @"SUBQUERY(tasks, $task, $task.completionDate != nil AND $task.user = 'Alex') .@count > 0"]

Assume this was run on an array of projects. It will return projects with tasks that were not completed by user Alex


Tips, Tricks, & Examples

Common mistakes

Using [NSString stringWithFormat:] to build predicates is prone to have non-escaped diacritics or artifacts like an apostrophe. Use [NSPredicate predicateWithFormat:] instead.

Using OR OR OR instead of IN, results in repeatable code and can be less efficient

When using REGEX and Matches, make sure they are the last part of your predicate statement so it does less work. This way objects will be filtered before doing more heavy look ups.

Using SELF

When using a predicate on an array, SELF refers to each object in the array. Here’s an example: Imagine you are a landlord figuring out which apartments have to pay their water bill. If you have a list of all the city wide apartments that still need to pay called addressesThatOweWaterBill, we can check that against our owned apartments, myApartmentAddresses.

NSPredicate *billingPredicate = [NSPredicate predicateWithFormat: @"SELF IN %@", addressesThatOweWaterBill]

NSArray *myApartmentsThatOweWaterBill = [myApartmentAddresses filteredArrayUsingPredicate:billingPredicate]

* matches 0 or more characters. For example: Let’s say we have an array of names we want to filter

@[@"Sarah", @"Silva", @"silva", @"Silvy", @"Silvia", @"Si*"]

predicateWithFormat: @"SELF == %@", @"Sarah"

Will return “Sarah”

predicateWithFormat: @"SELF LIKE[c] %@", "Si*"

Will return “Silva”, “silva”, “Silvy”, “Silvia”, “Si*”
? matches 1 character only

predicateWithFormat: @"SELF LIKE[c] %@", "Silv?"

Will return “Silva”, “silva”, “Silvy”

Quick tips

CFStringTransform normalizes strings if diacritic insensitive isn’t enough. For example you could turn Japanese characters into a Latin alphabetic representation. It’s extremely powerful with a lot of methods that you can see here: http://nshipster.com/cfstringtransform/

Make sure your columns are indexed to improve performance of using IN operators

[c] case insensitive: lowercase & uppercase values are treated the same

[d] diacritic insensitive: special characters treated as the base character

predicateWithFormat: @"name CONTAINS[c] 'f'"

Keypath collection queries

Keypath collection queries work best when you work with a lot of numbers. Being able to call the min or max, adding things up, and then filtering results are simpler when you only have to append an extra parameter. By having an array of expenses, you can do a quick check on if something is below or above a range of allowed expenses.

[NSPredicate predicateWithFormat: @"expenses.@avg.doubleValue < 200"]

How subqueries work

SUBQUERY(collection, variableName, predicate)

A subquery takes a collection then iterates through each object (as variableName) checking the predicate against that object. It works well if you have a collection (A) objects, and each object has a collection (B) other objects. If you’re trying to filter A based on 2 or more varying attributes of B.

predicateWithFormat: @"SUBQUERY(tasks, $task, $task.completionDate != nil AND $task.user = 'Alex') .@count > 0"

SUBQUERY(…) returns an array. We need to check if its count > 0 to return the true or false value predicate expects.