I'm trying to fetch objects from core data that are not in a given set, but I haven't been able to get it to work.
For instance, suppose that we have a core data entity named User, which has a few attributes such as userName, familyName, givenName, and active. Given an array of strings representing a set of usernames, we can easily fetch all the users corresponding to that list of usernames:
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"User"
inManagedObjectContext:moc];
[request setEntity:entity];
NSArray *userNames = [NSArray arrayWithObjects:#"user1", #"user2", #"user3", nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"userName IN %#", userNames];
[request setPredicate:predicate];
NSArray *users = [moc executeFetchRequest:request error:nil];
However, I want to fetch the complement of that set, i.e., I want all the users in core data that don't have the usernames specified in the userNames array. Does anyone have an idea how to approach this issue? I thought it would be simple enough to add a "NOT" in the predicate (i.e., "userName NOT IN %#"), but Xcode throws an exception saying the predicate format could not be parsed. I also tried using the predicate builder available for fetch requests with no luck. The documentation wasn't particularly helpful either. Suggestions? Comments? Thanks for all your help :)
In order to find the objects that aren't in your array, all you have to do is something like this:
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"NOT (userName IN %#)", userNames];
That should return a request of all the objects without the ones you specified
I am not strong at core data/objective-c but the predicate should be like the following statement;
[predicateFormat appendFormat:#"not (some_field_name in {'A','B','B','C'})"];
An example:
NSMutableString * mutableStr = [[NSMutableString alloc] init];
//prepare filter statement
for (SomeEntity * e in self.someArray) {
[mutableStr appendFormat:#"'%#',", e.key];
}
//excluded objects exist
if (![mutableStr isEqual:#""])
{
//remove last comma from mutable string
mutableStr = [[mutableStr substringToIndex:mutableStr.length-1] copy];
[predicateFormat appendFormat:#"not (key in {%#})", mutableStr];
}
//...
//use this predicate in NSFetchRequest
//fetchRequest.predicate = [NSPredicate predicateWithFormat:predicateFormat];
//...
Here's another useful example, showing how to take a list of strings, and filter out any which DON'T start with the letters A-Z:
NSArray* listOfCompanies = [NSArray arrayWithObjects:#"123 Hello", #"-30'c in Norway", #"ABC Ltd", #"British Rail", #"Daily Mail" #"Zylophones Inc.", nil];
NSPredicate *bPredicate = [NSPredicate predicateWithFormat:#"NOT (SELF MATCHES[c] '^[A-Za-z].*')"];
NSArray *filteredList = [listOfCompanies filteredArrayUsingPredicate:bPredicate];
for (NSString* oneCompany in filteredList)
NSLog(#"%#", oneCompany);
I use this kind of NSPredicate when I'm populating a UITableView with an A-Z index, and want an "everything else" section for items which don't start with a letter.
Related
I have Core Data setup in my app and need to fetch a bunch of items and then access the properties I choose of those fetched items. I am able to successfully fetch a bunch of results like this:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"TableInfo" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSError *error = nil;
NSArray *result = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
This gives me an array with my results, great. Now from this how can I for example get the 'name' property from these results? In this specific circumstance I want to load an array with all of the fetched results 'name' strings.
If I read your question correctly, you are able to fetch your NSManagedObjects without difficulty, but would like to derive another NSArray with name properties on those managed objects?
Then you can use the valueForKeyPath on the NSArray (extending your original code):
NSArray *names = [result valueForKeyPath:#"name"];
You can use the key-value:
for (NSManagedObject *fetchedResult in result) {
NSLog(#"name = %#", [fetchedResult valueForKey:#"name"]);
}
or if you created your custom NSManagedObject:
for (EntityObject *fetchedResult in result) {
NSLog(#"name = %#", [fetchedResult name]);
}
I have a managed object with two dates: dateOne and dateTwo and I want to retrieve the dates where dateTwo is older than dateOne.
Right now I am using the following predicate to fetch the objects:
NSArray *objects = nil;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:#"Object" inManagedObjectContext:context];
request.predicate = [NSPredicate predicateWithFormat:#"dateOne > dateTwo", #""];
objects = [context executeFetchRequest:request error:nil];
[request release];
Sometimes it works, but other times the objects fetched have a dateTwo that is more recent than dateOne. Is there a better way to do something like this?
Thanks!
Perhaps you could add a BOOL property "dateTwoIsOlder" to the entity, then just fetch objects that adhere to that?
Why not just create a fetch request from core data and not do it programmatically?
Say I have a Core Data entity called Person. How would I get an NSArray of Persons whose properties match certain values? For instance someone of a particular age, height, or weight... or someone with a whose height,weight and age are specific values...
Can I use an NSPredicate like so:
NSPredicate *pred =
[NSPredicate predicateWithFormat:
#"(age == 25) OR (height_in_cms == 185) OR (age == 30 AND height_in_cms == 170 AND weight_in_kgs == 80)";
// All properties are NSNumber
I'm not an expert on the syntax for predicateWithFormat:, but you have the basic gist. You can find details on the format in Apple's Predicate Programming Guide. If you're asking what to do with the predicate once you have it, here is a snippet that shows you the steps:
// Create a fetch request.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Set the entity for the fetch request.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"EntityName" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
[entity release];
// Set the predicate for the fetch request.
[fetchRequest setPredicate:predicate];
// Perform the fetch.
NSError *error;
NSArray *array = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
If you want the results to be sorted, you can pass an array of sort descriptors to the fetch request using setSortDescriptors: prior to executing the fetch.
You can follow the given statement if you have these value in a variable.
[fetchResults filterUsingPredicate:[NSPredicate predicateWithFormat:#"age == %i OR hieght== %i AND weight==%i",age,height,weight]];
And also your approach is correct in case for specific values but your statement having syntax error so maintain proper syntax
So, I've got a one-to-many relationship of Companies to Employees in CoreData (using a SQLite backend on iOS, if that's relevant). I want to create a predicate that only returns Companies that have 0 Employees associated with them. I could do it by getting all the Companies and iterating over them, but that would be (I assume) much slower.
Any ideas?
Thanks,
-Aaron
After trying #falconcreek's answer and getting an error (described in my comment on his answer), I did some googling and determined that the answer was
NSPredicate *noEmployeesPredicate = [NSPredicate predicateWithFormat:#"employees.#count == 0"];
Now everything works über efficiently. Thanks!
Assuming your Company -> Employee relationship is named "employees"
NSManagedObjectContext *moc = [self managedObjectContext];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Company" inManagedObjectContext:moc];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:entityDescription];
// the following doesn't work
// NSPredicate *noEmployeesPredicate = [NSPredicate predicateWithFormat:#"employees = nil OR employees[SIZE] = 0"];
// use #count instead
NSPredicate *noEmployeesPredicate = [NSPredicate predicateWithFormat:#"employees = nil OR employees.#count == 0"];
[request setPredicate:predicate];
NSError *error = nil;
NSArray *array = [moc executeFetchRequest:request error:&error];
if (error)
{
// Deal with error...
}
I have the need to create a complex predicate for an abstract base object. I want to have separate predicate queries for different inheriting entities and key off the sub-entity type, the example below is what I would like to do, however, I have not been able to find a way to reference the entity name or type in the predicate.
NSFetchRequest *request = [[NSFetchRequest alloc] init];
request.entity = [NSEntityDescription entityForName:#"MyCommonObjectBase" inManagedObjectContext:myContext];
NSPredicate *subclassAPredicate = [NSPredicate predicateWithFormat:#"someValue > %# && entityName = %#", 100, #"SubclassA"];
NSPredicate *subclassBPredicate = [NSPredicate predicateWithFormat:#"someValue < %# && entityName = %#", 50, #"SubclassB"];
request.predicate = [NSCompoundPredicate orPredicateWithSubpredicates:[NSArray arrayWithObjects:subclassAPredicate, subclassBPredicate, nil]];
I got a response from Apple at http://bugreport.apple.com problem number 7318897:
entity.name is not a modeled property, so it's not legal. it works by accident on the binary store. The correct way to fetch subentities is to do so on the NSFetchRequest and use either setIncludesSubentities or not.
So it seems the proper solution is to have separate fetch requests and to merge the result sets after execution.
A shot in the dark here, but what about using the className value in the predicate?
NSPredicate *subclassAPredicate = [NSPredicate predicateWithFormat:#"someValue > %d AND child.className = %#", 100, #"SubclassA"];
(Notice that you had an error in your predicate format. You were using %# to try and substitute in an integer value (100). %# is only used for objects. Use %d (or some other flavor) for primitives)
EDIT Found it!
You'll want to do this:
NSPredice * p = [NSPredicate predicateWithFormat:#"entity.name = %#", #"SubclassA"];
I just tested this on one of my apps and it seems to work.
-Another edit-
Here's the test that I ran, which seemed to work:
NSManagedObjectContext * c = [self managedObjectContext];
NSFetchRequest * f = [[NSFetchRequest alloc] init];
[f setEntity:[NSEntityDescription entityForName:#"AbstractFolder" inManagedObjectContext:c]];
[f setPredicate:[NSPredicate predicateWithFormat:#"entity.name = %#", #"DefaultFolder"]];
NSError * e = nil;
NSArray * a = [c executeFetchRequest:f error:&e];
[f release];
NSLog(#"%#", a);
When I run that, a logs two NSManagedObjects, both of the #"DefaultFolder" variety (which is what I was expecting). (AbstractFolder is an abstract entity. One of the child entities that inherits from it is a DefaultFolder)
The only way of associating a predicate with an entity I know of like is this:
NSPredicate * predicate = [NSPredicate predicateWithFormat: #"(%K == %#)", fieldName, fieldValue, nil];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setEntity:[NSEntityDescription entityForName:entityName inManagedObjectContext:managedObjectContext]];
[request setPredicate:predicate];
Maybe you were referring to the field name?
Edit: the entity is associated with the request, not with the predicate.