NSPredicate for an NSManagedObject's string attribute's length - core-data

Could someone please help me define a predicate that returns only NSManagedObject's who's "letters" attribute length is within a certain range?
Here's the example I've been trying, I've got a feeling it's the letters.length notation, I've also tried the kvc letters.#length with no success.. What am I doing wrong?
NSManagedObjectContext *context = ...;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Word" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"letters" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"letters.length BETWEEN %#", [NSArray arrayWithObjects: [NSNumber numberWithInt:5], [NSNumber numberWithInt:20], nil]];
[fetchRequest setPredicate:predicate];
NSUInteger limit = 20;
[fetchRequest setFetchLimit:limit];
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];

Not sure how this code snippet is performance wise but here is my answer to your question:
NSString *attributeName = #"letters";
NSString *attributeValue = [NSString stringWithFormat:#"'.{%d,%d}'", 5, 20];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K MATCHES %#", attributeName, attributeValue];
[fetchRequest setPredicate:predicate];
Joss.

I've got some bad news. You can't do this. There is no length attribute for strings in the NSPredicate (that I've been able to find).
What I would recommend you do is add an attribute for the length of the stored string in your managed object that gets set when you set the letters attribute. You can then do your query on that attribute and return the values you want.

In case someone is looking for a way to test whether a string has length using an NSPredicate,
it is possible.

Swift:
returns strings with 4 to 7 characters.
NSPredicate(format: "text MATCHES %#", ".{4,7}")

Related

Predicate Subquery to display entity with at least 1 common object in relationship

In a section of my data model I'm using -
Department <-->> Person <<-->> Project
I want to list all person's of departmentA that have at least 1 project in common with persons in departmentB. For example, of the list of projects personA has there needs to be at least 1 person from departmentB who also has the project. If a personB also has that project then personA is on the list. I've been struggling for a while with subquery and the direction I'm going is below. It fails with 'to-many key not allowed' other attempt have given me 'parse issue'.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Project" inManagedObjectContext:_managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"projectToPerson.personToDepartment = %#", departmentB];
[fetchRequest setPredicate:predicate];
NSError *error = nil;
NSArray *projects = [_managedObjectContext executeFetchRequest:fetchRequest error:&error];
NSFetchRequest *fetchRequest2 = [[NSFetchRequest alloc] init];
NSEntityDescription *entity2 = [NSEntityDescription
entityForName:#"Person" inManagedObjectContext:_managedObjectContext];
[fetchRequest2 setEntity:entity2];
NSPredicate *predicate2 = [NSPredicate predicateWithFormat:#"personToDepartment = %# AND SUBQUERY(personToProject, $x, $x.projectName = %#).#count >0", departmentA,projects];
[fetchRequest2 setPredicate:predicate2];
I'm attempting to get an array of all projects and then list all persons of departmentA with a project that matches. Is this possible, and is this the right direction?

How do I filter my array to display only specific category items?

This code currently lists all my categories. However I will like to filter this result to display specific results. For example... The array contains the items Jamaica, Japan, Germany and Asia. I will like to filter the displayed results to only show Japan and Germany. I've read NSPredicate can assist me but i'm not too sure on how to implement it here.
Datacontroller.M
+(NSArray*) getCategories {
AppDelegate* delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
NSManagedObjectContext* context = delegate.managedObjectContext;
NSError *error;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setReturnsObjectsAsFaults:NO];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"StoreCategory" inManagedObjectContext:context];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"created_at" ascending:YES];
[fetchRequest setSortDescriptors:#[sortDescriptor]];
[fetchRequest setEntity:entity];
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
return fetchedObjects;
}
Categories.m
-(UITableViewCell*)MGListView:(MGListView *)listView1 didCreateCell:(MGListCell *)cell indexPath:(NSIndexPath *)indexPath {
if(cell != nil) {
StoreCategory* cat = [listViewMain.arrayData objectAtIndex:indexPath.row];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.backgroundColor = [UIColor clearColor];
[cell.labelTitle setText:cat.category];
[self setImage:cat.category_icon imageView:cell.imgViewThumb];
}
return cell;
}
You cannot filter the unwanted category in this method because indexPath will be a sequence of indices.
You will have to build another array that includes the category you want before UITableView delegate or DataSource functions are called, for example, in ViewDidLoad.
This method seemed to do the trick.
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"category CONTAINS[cd] %# OR category CONTAINS[cd] %#", #"Japan", #"Germany", context];
[fetchRequest setPredicate:predicate];

NSPredicate with 20 last records

I'm working with core data and I try to get last 20 records using setFecthLimit but in these last records I want to get count of unreads, I use this
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Post" inManagedObjectContext:_managedObjectContext];
[request setEntity:entity];
[request setFetchLimit:20];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"isRead = NO OR isRead = NIL"];
[request setPredicate:predicate];
NSError *error = nil;
NSMutableArray *records = [[_managedObjectContext
executeFetchRequest:request
error:&error] mutableCopy];
but it always return me 20, can anyone help me please?
A simple solution is to remove the predicate. Grab 20 objects and then filter them based on the predicate.
For example:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Post" inManagedObjectContext:_managedObjectContext];
[request setEntity:entity];
[request setFetchLimit:20];
NSError *error = nil;
NSArray *records = [_managedObjectContext executeFetchRequest:request
error:&error];
// do some error checking here...
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"isRead = NO OR isRead = nil"];
// [NSPredicate predicateWithFormat:#"isRead = %#", [NSNumber numberWithBool:NO]];
NSArray *filteredRecords = [records filteredArrayUsingPredicate:predicate];
I think you have a typo in your predicate format:
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"Post"]
request.fetchLimit = 20;
request.predicate = [NSPredicate predicateWithFormat:#"(isRead == NO) OR (isRead == NULL)"];
NSSortDescriptor = [...insert your sort descriptor code here...]
request.sortDEscriptos = #[sd];
And remember to sort, such that you get the last 20, not just a random 20.

Core Data: NSPredicate for many-to-many relationship. ("to-many key not allowed here")

I have two entities named "Category" and "Article" which have a many to many relationship. I want to form a predicate which searches for all articles where category.name is equal to some value. I have the following:
NSEntityDescription *entityArticle = [NSEntityDescription entityForName:#"Article" inManagedObjectContext:managedObjectContext];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"title" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"categories.name == [cd] %#", category.name];
[request setSortDescriptors:sortDescriptors];
[request setEntity:entityArticle];
[request setPredicate:predicate];
NSMutableArray *results = [[managedObjectContext executeFetchRequest:request error:nil] mutableCopy];
if ([results count] > 0)
NSLog(#"Results found.");
else
NSLog(#"NO results found.");
[request release];
[sortDescriptor release];
[sortDescriptors release];
The error I receive is *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'to-many key not allowed here'
Are there any options to retrieve the desired data?
You're trying to compare a collection (categories.name) to a scalar value (category.name). You need to either use a collection comparator (CONTAINS), or use a predicate modifier (ANY/ALL/SOME, etc).
Try using:
[NSPredicate predicateWithFormat:#"ANY categories.name =[cd] %#", category.name];
Or:
[NSPredicate predicateWithFormat:#"categories.name CONTAINS[cd] %#", category.name];
SWIFT SYNTAX
In case anyone happens upon this writing in swift as I did...
let predicate = NSPredicate(format: "ANY categories.name = %#", category.name!)
fetchRequest.predicate = predicate
worked for me.
For those who faced the same problem. You can use IN operator instead of = / == to look for specific objects in any Collection.
Look here for reference. No difference Swift or Objective-C

CoreData: fetch only last elements, not all (iPhone)

Welcome
i use Core Data to store datas. i need such a method which returns only the last 7 elements of entity. my question is how should i modify this code ( it fetchs all of elements, but i need only last 7)
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Trip" inManagedObjectContext:managedObjectContext];
NSFetchRequest *request = [[ NSFetchRequest alloc] init];
[request setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"distance" ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[request setSortDescriptors:sortDescriptors];
[sortDescriptor release];
NSError *error;
tripArray = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
Define last? Core Data does not have a concept of order internally. If you mean by the farthest away based on your distance property then you can do the following:
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Trip" inManagedObjectContext:managedObjectContext];
NSFetchRequest *request = [[ NSFetchRequest alloc] init];
[request setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"distance" ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[request setSortDescriptors:sortDescriptors];
[request setFetchLimit:7];
[sortDescriptor release];
NSError *error;
NSArray *tripArray = [managedObjectContext executeFetchRequest:request error:&error];
Note that the addition of the -setFetchLimit: will cause this request to only return 7 results. It will return the "first" 7 based on your sort. So if you want the closest, reverse the ascending: portion of your sort.
-mutableCopy
There is absolutely no point in calling -mutableCopy on the NSArray that is returned from -executeFetchRequest: error:. Adding objects to that NSArray will not add them to Core Data and removing them from that NSArray will not remove them from Core Data. Therefore it has absolutely no value and is just wasteful.
Do you remember where you saw that? I have been trying to track it down for a while now.

Resources