Reputation: 2037
I have a Core Data object with several attributes, one of which is called Category. This is a string that could take on any value, nothing that I can guarantee any knowledge of up front. I want to run a fetch that will return a list of Category values that are shared across all stored elements whose Tag value matches a given value. I'm not sure how to best describe this, so here's an example:
ObjectNumber Tag Category
---------------------------------
01 AAA Red
02 AAA Green
03 AAA Blue
04 BBB Blue
05 BBB Red
06 BBB Yellow
07 CCC Blue
08 CCC Yellow
09 CCC Red
I want the results of my fetch to be a list of Categories that are shared across all objects whose Tag is in the set {AAA, BBB, CCC}, which in this case, would return ["Red", "Blue"], because those are the only categories shared among any objects whose tag is in the given set.
I'm hoping to find something that's as fast as possible, because when this app is run on a real project, there will be tens of thousands of objects in the database.
Upvotes: 0
Views: 98
Reputation: 2387
Here is a code sample I just wrote up, that should solve your filtration question.
I'm still learning the intricacies of NSFetchRequest and predicates, although it's not very complicated, after reading the documentation and experimenting.
NSArray *setoftags = [NSArray arrayWithObjects: @"AAA", @"BBB", nil];
NSFetchRequest * request;
NSMutableSet *tagcategoriesset = nil;
for (NSString *tag in setoftags) {
request = [NSFetchRequest fetchRequestWithEntityName:@"ObjectWithCategories"];
NSPredicate *tagPredicate = [NSPredicate predicateWithFormat:@"%K == %@", @"Tag", tag];
request.predicate = tagPredicate;
NSArray *objects;
NSError *err;
NSMutableSet *tagcategories = [[NSMutableSet alloc] initWithCapacity:1];
if ( (objects = [self.managedObjectContext executeFetchRequest:request error:&err]) == nil) {
// error
NSLog(@"There was an error:\n%@", [err localizedDescription]);
}
else {
// fetch request succeeded
// Ignore any unused tags
if ( [objects count] == 0) continue;
// Collect the Category attribute into a mutable set
for(NSManagedObject *obj in objects) {
[tagcategories addObject: [(id)obj Category]];
}
// First assign, later intersect the tagcategories
if (tagcategoriesset == nil) {
tagcategoriesset = tagcategories;
}
else {
[tagcategoriesset intersectSet: tagcategories];
}
}
}
NSArray *finalCategories = [tagcategoriesset allObjects];
Here's another SO Q&A for further discussion: using NSPredicate with a set of answers
Upvotes: 2
Reputation: 3791
These are all good articles that helped me better understand NSPredicate
. I highly recommend these as worthwhile reading.
NSHipster by Mattt Thompson
Using NSPredicate to Filter Data by Peter Friese
This is an example of a simple NSPredicate
...
NSString *key = @"Category";
NSString *value = @"Red";
[NSPredicate predicateWithFormat:@"%K == %@", key, value]
This is an example of a more complicated NSPredicate
...
NSString *key = @"Category";
NSString *value1 = @"Red";
NSString *value2 = @"Blue";
NSPredicate *predicateRed = [NSPredicate predicateWithFormat: @"%K == %@", key, value1];
NSPredicate *predicateBlue = [NSPredicate predicateWithFormat: @"%K == %@", key, value2];
NSPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:@[predicateRed, predicateBlue]];
I used this format to demonstrate what can be achieved. To be clear this second example could also be more simply written...
NSPredicate *predicate = [NSPredicate predicateWithFormat: @"(%K == %@) || (%K == %@)", key, value1, key, value2];
These examples are not intended to be the solution, however are provided to demonstrate the mechanics to help you develop a solution.
Hope that helps.
Upvotes: 1