Back again needing more help with constructing my NSPredicates :(
Category
{
name:string
subs<-->>SubCategory
}
SubCategory
{
name:string
numbervalue:NSNumber
}
I would like to know how to create a predicate with AND and OR.
For example, I would like to return every Category with name == "category_name" that also has a subcategory with a numbervalue of "valueA" OR "valueB".
I've tried every possible combination of predicate constructors I could come up with but I just cant get it to work.
This is my best attempt so far.
NSPredicate *predicate=[NSPredicate predicateWithFormat@"(name== %@) AND (ANY subs.numbervalue==%@ OR ANY subs.numbervalue==%@)", @"aname", value1, value2];
Edit 1
Second attempt. The filtering on the 'numbervalue' is still not working.
NSNumber valueA=[NSNumber numberWithInt:20];
NSNumber valueA=[NSNumber numberWithInt:90];
NSArray *arr=[NSArray arrayWithObject:valueA,valueB,nil];
predicate=[NSPredicate predicateWithFormat:@"(name==%@)AND(ANY subs.numbervalue IN %@)",@"aname",arr];
Edit 2
I've tried filtering just by numberValue and have left the name out alltogether.
1) using this results in the entire set being returned even if only 1 item in the set has the value.
predicate=[NSPredicate predicateWithFormat:@"(ANY subs.numbervalue IN %@)",arr];
2) Using this results in the same problem, every item in the set being returned even if only 1 of them matches.
predicate=[NSPredicate predicateWithFormat:@"((SUBQUERY(subs, $x, $x.numbervalue == %@ or $x.numbervalue == %@).@count > 0)", value1, value2];
Also using the simplest version results in the same problem.... I didnt notice this earlier.
NSPredicate *predicate=[NSPredicate predicateWithFormat@"(ANY subs.numbervalue==%@ ,valueA];
So I think I have my problem narrowed down.
Category is an Entity. SubCategory is an Entity.
Category has a one to many relationship with SubCategory and is represented as an NSSet of SubCategory.
Each SubCategory has an attribute named numbervalue.
Edit 3
To test I have 2 Categorys. Both Categories have 10 subs, each with a numbervalue of 1 -10;
Using this code both categories are returned along with all 10 subs for each.
Expected result is both categories returned , each with just 2 subs.
I've traced out all my objects and the data is correct. The problem is I cant return a category that has filtered subs.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSManagedObjectContext *context=[[DataSource sharedDataSource]managedObjectContext];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Category" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
NSPredicate *predicate;
NSNumber *a=[NSNumber numberWithFloat:1];
NSNumber *b=[NSNumber numberWithFloat:2];
predicate=[NSPredicate predicateWithFormat:@"(SUBQUERY(subs,$x,$x.numbervalue==%@ or $x.numbervalue==%@).@count> 0)",a,b];
[fetchRequest setPredicate:predicate];
[fetchRequest setSortDescriptors:sortDescriptors];
NSError *error = nil;
[NSFetchedResultsContoller deleteCacheWithName:nil];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:context sectionNameKeyPath:@"name" cacheName:@"Master"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
if (![self.fetchedResultsController performFetch:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
Addition to @Stuart's answer, you can use NSCompoundPredicate for your OR & AND operations like this.
Obj-C - OR
// OR Condition //
NSPredicate *predicate1 = [NSPredicate predicateWithFormat:@"X == 1"];
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@"X == 2"];
NSPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:@[predicate1, predicate2]];
Obj-C - AND
NSPredicate *predicate1 = [NSPredicate predicateWithFormat:@"X == 1"];
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@"X == 2"];
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[predicate1, predicate2]];
Swift - OR
let predicate1:NSPredicate = NSPredicate(format: "X == 1")
let predicate2:NSPredicate = NSPredicate(format: "Y == 2")
let predicate:NSPredicate = NSCompoundPredicate(orPredicateWithSubpredicates: [predicate1,predicate2] )
Swift - AND
let predicate1:NSPredicate = NSPredicate(format: "X == 1")
let predicate2:NSPredicate = NSPredicate(format: "Y == 2")
let predicate:NSPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [predicate1,predicate2] )
Swift 3 - OR
let predicate1 = NSPredicate(format: "X == 1")
let predicate2 = NSPredicate(format: "Y == 2")
let predicateCompound = NSCompoundPredicate.init(type: .or, subpredicates: [predicate1,predicate2])
Swift 3 - AND
let predicate1 = NSPredicate(format: "X == 1")
let predicate2 = NSPredicate(format: "Y == 2")
let predicateCompound = NSCompoundPredicate.init(type: .and, subpredicates: [predicate1,predicate2])