mikemike396
mikemike396

Reputation: 2495

How to use the “ANY” aggregate operation in a NSPredicate to filter a CoreData Many To Many Relationship

Data Model:

enter image description here

enter image description here

enter image description here

I am trying to fetch all of the "Solutions" that have contentType.selected == 1

Proof that structure and data is setup correctly

--ContentType Entity Data Content Type Entity Data

--Solution Entity Data

enter image description here

--ContentType Relationship

enter image description here

Sanity Check (No Predicate)

(lldb) po self.solutionTreeFetchedResultsController.fetchedObjects
<_PFArray 0x7fe958ea2b10>(
<Solutions: 0x7fe95b1415e0> (entity: Solutions; id: 0xd00000000ac00006 <x-coredata://2799F23D-B41B-48EF-923A-9E2C2A0C10B5/Solutions/p688> ; data: <fault>),
<Solutions: 0x7fe95b141b10> (entity: Solutions; id: 0xd00000000ac40006 <x-coredata://2799F23D-B41B-48EF-923A-9E2C2A0C10B5/Solutions/p689> ; data: <fault>)

......Cut off the rest but there are 49 here.)

(lldb) po [self.solutionTreeFetchedResultsController.fetchedObjects count]
49

Method 1 (Most Straight Forward)

NSArray *contentTypes = self.contentTypeFetchedResultsController.fetchedObjects;
request.predicate = [NSPredicate predicateWithFormat:@"ANY contentType IN %@", contentTypes];

po contentTypes
<_PFArray 0x7fa4b6018680>(
<ContentType: 0x7fa4b60181c0> (entity: ContentType; id: 0xd0000000006c0004 <x-coredata://2799F23D-B41B-48EF-923A-9E2C2A0C10B5/ContentType/p27> ; data: <fault>),
<ContentType: 0x7fa4b6018620> (entity: ContentType; id: 0xd000000000700004 <x-coredata://2799F23D-B41B-48EF-923A-9E2C2A0C10B5/ContentType/p28> ; data: <fault>)
)

po self.solutionTreeFetchedResultsController.fetchedObjects
<__NSArrayI 0x7fa4b3c1ddf0>(

)

Method 2

 request.predicate = [NSPredicate
                         predicateWithFormat:@"SUBQUERY(contentType, $contenttype, $contenttype IN %@).@count = %d", contentTypes, [contentTypes count]];

(lldb) po self.solutionTreeFetchedResultsController.fetchedObjects
<__NSArrayI 0x7fcea3e01350>(

)

Method 3

NSMutableArray *predicates = [[NSMutableArray alloc] init];
for (ContentType *contentType in contentTypes) {
    [predicates addObject:[NSPredicate predicateWithFormat:@"ANY contentType.name MATCHES %@", contentType.name]];
}

[predicates addObject:[NSPredicate predicateWithFormat:@"active == 1"]];
NSPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:predicates];
request.predicate = compoundPredicate;

(lldb) po self.solutionTreeFetchedResultsController.fetchedObjects
<__NSArrayI 0x7f8f9850bbf0>(

)

Method 3 sorta works if you select only 1 contentType, but if you have more than 1 selected it returns nothing.

I am lost and not sure what else to try. Any input would be greatly appreciated! If you need anything else let me know. Thanks!

Have tried most of these solutions from this post and nothing seems to work 100% How to use the "ALL" aggregate operation in a NSPredicate to filter a CoreData-based collection

Upvotes: 1

Views: 474

Answers (1)

user3845832
user3845832

Reputation:

If your question is how to fetch all of the "Solutions" that have contentType.selected == 1 with the given data model, the predicate:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(ANY contentType.selected == $SELECTVALUE)"];

works for me. Defining it as a template and adding it to the model like this ....

- (NSManagedObjectModel *)managedObjectModel {
 // The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
 if (_managedObjectModel != nil) {
     return _managedObjectModel;
 }
 NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"ANYApp" withExtension:@"momd"];

 _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

 NSEntityDescription *entity = [[_managedObjectModel entitiesByName] objectForKey:@"Solutions"];

 NSFetchRequest *template = [[NSFetchRequest alloc] init];

 [template setEntity:entity];

 NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(ANY contentType.selected == $SELECTVALUE)"];

 [template setPredicate:predicate];

 [_managedObjectModel setFetchRequestTemplate:template forName:@"SolutionsTemplate"];

 return _managedObjectModel;
}

Defining fetch method like this ....

- (NSArray *)fetchAllSolutionsBySelected:(NSNumber *)selected
 {
  NSError *error = nil;

 NSString *templateName=@"SolutionsTemplate";

 NSDictionary *substitutionDictionary = [NSDictionary dictionaryWithObjectsAndKeys:selected, @"SELECTVALUE", nil];

 NSFetchRequest *fetchRequest = [[_app managedObjectModel] fetchRequestFromTemplateWithName:templateName substitutionVariables:substitutionDictionary];

 NSArray *results = [[_app managedObjectContext] executeFetchRequest:fetchRequest error:&error];

 return results;
}

I could finally fetch all of the "Solutions" that have contentType.selected == 1:

NSArray *solutionsWithContentSelected=[self fetchAllSolutionsBySelected:@(1)];

You can find a XCode 6.1 iOS 8.1 project here: ANYApp Project. I hope it helps.

Upvotes: 1

Related Questions