Apologies if this is a duplicate, 20 minutes of searching didn't yield this exact situation or a solution.
I have a Core Data stack with three classes XClass
, YClass
, and ZClass
. XClass
has a one-to-many relationship with YClass
. YClass
has a one-to-many relationship with ZClass
.
Using an instance of NSFetchedResultsController
, I'm trying to fetch all instances of XClass
for which at least 1 YClass
has at least 1 ZClass
.
My predicate is defined as follows:
// ...stuff
NSFetchRequest * fetchRequest = [NSFetchRequest new];
NSEntityDescription * entity = [NSEntityDescription entityForName:NSStringFromClass([XClass class])
inManagedObjectContext:managedObjectContext];
fetchRequest.entity = entity;
fetchRequest.predicate =
[NSPredicate predicateWithFormat:@"0 < SUBQUERY(yObjects, $y, $y.zObjects.@count > 0).@count"];
// ..instantiate NSFetchedResultsController and perform fetch
This causes a fatal exception with the message: Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Keypath containing KVC aggregate where there shouldn't be one; failed to handle $y.zObjects.@count'
Elsewhere, I've successfully fetched YObject
instances with the predicate [NSPredicate predicateWithFormat:@"zObjects.@count > 0"];
Can someone point me to what I'm doing wrong? Thank you much.
It seems that NSPredicate objects violently when you use collection operators in the predicate string for the SUBQUERY. It also appears that you cannot operate on a collection in the subquery predicate. That is unless the variable represents a collection in the predicate.
BAD: SUBQUERY(yObjects, $y, $y.zObjects == NIL) > 0
OK: SUBQUERY(yObjects, $y, SUBQUERY($y.zObjects, $z, $z == NIL) > 0) > 0
The following expression will add all non-nil objects to the filtered collection returned by the SUBQUERY. In other words, the returned collection will contain all instances of XClass with instantiations of ZClass.
[NSPredicate predicateWithFormat:@"yObjects.@count > 0 AND (SUBQUERY(yObjects, $y, (SUBQUERY($y.zObjects, $z, $z != NIL).@count > 0)).count > 0)"];