There appears to be zero documentation about the SUBQUERY keyword from Apple and I can\'t find a simple explanation about it on SO or on Google. It\'s a conspiracy! ;)
This is what a subquery evaluates to. (Found from this mailing list thread, the #1 hit for “NSPredicate subquery” in Google.) That bit of documentation also explains how the predicate format string syntax relates to it.
Subquery represents a predicate (third argument - $x IN %@
) that is evaluated on all objects (second argument - $x
- it's like a variable name in foreach) of a relationship (first argument - Bs
). Similarly to regular query returns a list of objects.
I see in many places that people use $x
almost dogmatically, but $object
in objects
relationship makes perfect sense as well (or $city
in cities
...) :)
I've written a blog post about SUBQUERY
some time ago. You can check it here.
And for people who don't quite get what the documentation is saying, a SUBQUERY
is essentially this:
SUBQUERY(collection, variableName, predicateFormat)
And could (simplistically) be implemented like this:
id resultingCollection = ...; //a new collection, either a mutable set or array
NSMutableDictionary * substitutions = [NSMutableDictionary dictionary];
NSPredicate * p = [NSPredicate predicateWithFormat:predicateFormat];
for (id variable in collection) {
[substitutions setObject:variable forKey:variableName];
NSPredicate * filter = [p predicateWithSubstitutionVariables:substitutions];
if ([filter evaluateWithObject:collection] == YES) {
[resultingCollection addObject:variable];
}
}
return resultingCollection;
So in a nutshell, a SUBQUERY
is basically taking a collection of objects and filtering out various objects based on the predicate expression of the SUBQUERY
, and returning the resulting collection. (And the predicate itself can contain other SUBQUERY
s)
Example:
NSArray * arrayOfArrays = [NSArray arrayWithObjects:
[NSArray arrayWithObjects:....],
[NSArray arrayWithObjects:....],
[NSArray arrayWithObjects:....],
[NSArray arrayWithObjects:....],
[NSArray arrayWithObjects:....],
[NSArray arrayWithObjects:....],
nil];
NSPredicate * filter = [NSPredicate predicateWithFormat:@"SUBQUERY(SELF, $a, $a.@count > 42)"];
NSArray * filtered = [arrayOfArrays filteredArrayUsingPredicate:filter];
//"filtered" is an array of arrays
//the only arrays in "filtered" will have at least 42 elements each