I'm writing an application with Core Data that have to maintain a catalog with 4 levels of hierarchy.
Category <--->> SubCategory <--->> Item <--->> SubItem
I have a screen (table/collection view) where Items are displayed along with Category and SubCategory titles. The Items could be.
Basically I have to display filtered catalog. Let's say Item have a name and I want to filter items by name.
Example.
Category: Category 1
SubCategory: SubCategory 1.1
Items: [aaa, bbb, ccc, abc, abd, abg]
SubCategory: SubCategory 1.2
Items: [aaa, bbb, ccc]
Category: Category 2
SubCategory: SubCategory 2.1
Items: [123ab, 456ab, 123, 345, 456]
After filtering with query 'ab' I want to see the following objects:
Category: Category 1
SubCategory: SubCategory 1.1
Items: [abc, abd, abg]
Category: Category 2
SubCategory: SubCategory 2.1
Items: [123ab, 456ab]
The thing is: I can't use fetch request against Category because it will only show me categories that contain items that satisfy criteria but it will not filter items.
I can directly fetch filtered collection of Item but I have to rebuild structure Category - SubCategory - Item and put it in some arrays/dictionaries etc.
Is there a better way to filter deeply nested hierarchy with CoreData?
The main question: is there a way to fetch leafs of deeply nested object tree while running fetch request against its root?
You can filter items using searchString by,
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]initWithEntityName:#"Item"];
NSPredicate *predicate = nil;
if([_searchBar.text length] > 0){
predicate = [NSPredicate predicateWithFormat:#"itemName CONTAINS[cd] %#", _searchBar.text];
}
if(predicate){
[fetchRequest setPredicate:predicate];
}
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]initWithKey:#"itemName" ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sortDescriptor]];
If you need to sort the result by considering category and subCategory, you can use more sort descriptors according to your priority like,
NSSortDescriptor *sortDescriptorCategory = [[NSSortDescriptor alloc]initWithKey:#"categoryName" ascending:YES];
NSSortDescriptor *sortDescriptorSubCategory = [[NSSortDescriptor alloc]initWithKey:#"subCategoryName" ascending:YES];
NSSortDescriptor *sortDescriptorItem = [[NSSortDescriptor alloc]initWithKey:#"itemName" ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sortDescriptorCategory, sortDescriptorSubCategory, sortDescriptorItem, nil]];
You can just separate each key with a '.' like so...
NSSortDescriptor *sortDescriptorSubCategory = [[NSSortDescriptor alloc]initWithKey:#"Category.SubCategory.Items" ascending:YES];
then, in iOS 7 +
[YOUR_ARRAY sortedArrayUsingDescriptors:#[sortDescriptorSubCategory]];
Or, older iOS versions
[YOUR_ARRAY sortedArrayUsingDescriptors:[NSArray sortDescriptorSubCategory, nil]];
Related
I am having problem with my core data's entity. It has three attributes similar to this table
Name value details
cat xxx 01
apple YYY 10
ball ZZZ 11
I need to sort the table based on attribute "Name" to make the entity look like this
Name value details
apple YYY 10
ball ZZZ 11
cat xxx 01
Using the below code only sorts the "name" attribute values, but i need the entire row to be sorted.
NSFetchRequest *fetchRequest1 = [NSFetchRequest fetchRequestWithEntityName:#"UserData"];
fetchRequest1.resultType = NSDictionaryResultType;
[fetchRequest1 setPropertiesToFetch:[NSArray arrayWithObjects:#"userName", nil]];
fetchRequest1.returnsDistinctResults = YES;
NSArray *dictionaries1 = [self.managedObjectContext executeFetchRequest:fetchRequest1 error:nil];
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:#"userName" ascending:YES selector:#selector(caseInsensitiveCompare:)];
NSArray* sortedArray=[dictionaries1 sortedArrayUsingDescriptors:#[sort]];
Is there a way to sort the entire row and save the entity ??
You have specified NSDictionaryResultType, so the fetch returns only the one attribute that you specify - username. To fetch the complete object, with all its attributes, delete those lines. You also don't need returnsDistinctResults. And you might as well get the fetch to do the sorting, rather than sorting the array afterwards:
NSFetchRequest *fetchRequest1 = [NSFetchRequest fetchRequestWithEntityName:#"UserData"];
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:#"userName" ascending:YES selector:#selector(caseInsensitiveCompare:)];
fetchRequest1.sortDescriptors = #[sort];
NSArray *sortedResults = [self.managedObjectContext executeFetchRequest:fetchRequest1 error:nil];
In my app I have two entities which are Items and Lists. Each item belongs to only one list and each list has many items. Thus in the modal the entities has the following relationships:
For Items: to-one relationship (belongs_to_list) pointing to one list
For Lists: to-many relationship (has_items) pointing to many items
How can I fetch the items using a predicate to check whether the list it's related to is equal to a specific list I provide? I don't want to fetch the items through the list (like fetching objects of has_items). I want to be able to use belongs_to_list in a predicate to compare it to a managed object I have. I tried the following but it's not working. Any help please?
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Items" inManagedObjectContext:_managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:#"item_detail" ascending:YES];
[fetchRequest setSortDescriptors:[NSArray arrayWithObject:sort]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"list.list_name == %#", [self.currentList valueForKey:#"list_name"]];
[fetchRequest setPredicate:predicate];
If I understood well your question, the following predicates would be correct:
[NSPredicate predicateWithFormat:#"belongs_to_list == %#", [self currentList]];
Let me know if this does work for you.
I have two entities in my core data model. Author and Book. An author can have many books.
This is the part I've got sorted out. It's all working.
Now I'd like to fetch my authors in alphabetical order:
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Author" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES];
NSArray *sortDescriptors = #[sortDescriptor];
[fetchRequest setSortDescriptors:sortDescriptors];
No problems so far. But now I would like to fetch all the author's books, ordered by release date.
When I fetch the author's books using the following line of code …
self.selectedAuthor.books.allObjects
… the order of books seems to be completely random.
My question:
How can sort an object's related entities when fetching them from the core data, so that every time I use self.selectedAuthor.books.allObjects, all books are ordered by (for example) release date?
You can add a method - (NSArray *)booksSortedByDate; to the Author class interface and in the implementation write code like this:
- (NSArray *)booksSortedByDate {
return [self.books.allObjects sortedArrayUsingDescriptors:#[[NSSortDescriptor sortDescriptorWithKey:#"releaseDate" ascending:YES]]];
}
You can't. The to-many relationship books is represented by an NSSet, which is an
unordered collection. You can either
Get the array of all books self.selectedAuthor.books.allObjects as you did,
and then sort this array in memory,
or
Execute a fetch request on the Book entity with the predicate
[NSPredicate predicateWithFormat:#"author = %#", self.selectedAuthor]
to get only books of that author, and add a sort descriptor to the fetch request
to get the books sorted by release date.
I have an NSFetchRequest that is fetching an entity called "Player" and I want the results be sorted by 3 attributes in the following order:
Whether the attribute called "sendingoffOffence" is nil or not
Whether the relationship in the entity at "team.homeMatch" is nil or not
I want the strings in the "number" attribute to be sorted in ascending order.
Basically, I am looking to have all players that have a red card ("sendingOffOffence" is not nil) appear at the top of the list, then have the set be ordered by whether the player is on the home team or not, and then finally get the set of players on a team in an offense group be sorted by their jersey numbers.
As such, I use the following code in my fetch request:
// Set the entity for the fetch request
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Player"
inManagedObjectContext:self.match.managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"match == %#", self.match];
[fetchRequest setPredicate:predicate];
// Sort the results
// Sort according to whether the user has a red card / sendingOffOffence
NSSortDescriptor *hasRedCard = [[NSSortDescriptor alloc] initWithKey:#"sendingoffOffence" ascending:NO];
// Sort according to whether the user is on the home team or not
NSSortDescriptor *isHomeTeam = [[NSSortDescriptor alloc] initWithKey:#"team.homeMatch" ascending:NO];
// Sort according to the player's jersey numbers
NSSortDescriptor *number = [[NSSortDescriptor alloc] initWithKey:#"number" ascending:YES selector:#selector(localizedStandardCompare:)];
[fetchRequest setSortDescriptors:#[hasRedCard, isHomeTeam, number]];
// Set the amount of records to retrieve from the database
[fetchRequest setFetchBatchSize:20];
NSFetchedResultsController *theFetchedResultsController =
[[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:self.match.managedObjectContext
sectionNameKeyPath:nil
cacheName:#"MatchCache"]
However, when I execute the above code, I get the following results:
This sorting order is wrong because I want the following order to appear in the red card section:
11 - Home
12 - Home
0 - Away
11 - Away
21 - Away
And in the yellow card section:
1 - Home
2 - Home
99 - Home
1 - Away
31 - Away
It looks like the yellow card section sorts correctly but the red card section is showing very weird behavior that makes it appear that it is not getting sorted at all.
I am fairly stumped as to why the red card section fails to sort correctly - any thoughts? Should I just sort these objects in memory instead of relying on core data to get my preferred order?
Please be aware that this is a core data application with a SQL backed persistence store.
UPDATE
The following is the SQL statement that core data is using in my fetch:
CoreData: annotation: fetch using NSSQLiteStatement <0x11c77cd0> on entity 'SPlayer' with
sql text 'SELECT t0.Z_ENT, t0.Z_PK FROM ZFSMANAGEDOBJECT t0 LEFT OUTER JOIN ZSTEAM t1 ON
t0.ZTEAM = t1.Z_PK WHERE ( t0.ZMATCH1 = ? AND t0.Z_ENT = ?) ORDER BY
t0.ZSENDINGOFFOFFENCE DESC, t1.ZHOMEMATCH DESC, t0.ZNUMBER COLLATE NSCollateFinderlike '
This is the line that is not being properly applied (for the RED card case):
NSSortDescriptor *isHomeTeam = [[NSSortDescriptor alloc] initWithKey:#"team.homeMatch" ascending:NO];
Without seeing your data model and some of the sample data, it's hard to say why this would not be sorting properly. I would assume this would put NIL values first, then proper values next (so sorting ascending NO would do what it's doing in the YELLOW card case).
If I was in this situation, I would check my assumptions about sort order and these team.homeMatch properties. Do a test where this is the only sort description.
Then focus in on what is different with the RED/YELLOW card condition.
We done without NSFetchedResultsController like this check it....
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Player"
inManagedObjectContext:self.match.managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"match == %#", self.match];
[fetchRequest setPredicate:predicate];
// Sort the results
// Sort according to whether the user has a red card / sendingOffOffence
NSSortDescriptor *hasRedCard = [[NSSortDescriptor alloc] initWithKey:#"sendingoffOffence" ascending:NO];
// Sort according to whether the user is on the home team or not
NSSortDescriptor *isHomeTeam = [[NSSortDescriptor alloc] initWithKey:#"team.homeMatch" ascending:NO];
[fetchRequest setSortDescriptors:#[hasRedCard, isHomeTeam]];
// Set the amount of records to retrieve from the database
[fetchRequest setFetchBatchSize:20];
NSArray *resultArray = [self.match.managedObjectContext executeFetchRequest:request error:&error];
NSSortDescriptor *number = [[NSSortDescriptor alloc] initWithKey:#"number" ascending:YES selector:#selector(localizedStandardCompare:)];
NSArray *sortedArray = [resultArray sortedArrayUsingDescriptors:[NSArray arrayWithObjects:number, nil]];
I have two entities as follows
Item <----->> Categories
Each item may have multiple categories.
For e.g. There are 5 items each have a sort category as release_Date. I want to sort all these 5 items based on the release_Date with the table view header as the release_Date value of each item.
I want to sort these items based on the category value selected by the user from the popover. Also I want to display the sorted objects in a sectioned table view with the table header being the category values selected.
I am using nsfetchedresultscontroller for this. I am able to sort the items based on the name of the items. But I am finding no luck in sorting them using the relationship attribute.
Any kind of help is appreciable.
if i understand your model correctly you can do this with multiple sort descriptors pretty easily.
NSSortDescriptor *sortDescriptor1 = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:NO];
NSSortDescriptor *sortDescriptor2 = [[NSSortDescriptor alloc] initWithKey:#"Categories.release_Date" ascending:NO];
NSArray *sortDescriptors = #[sortDescriptor1, sortDescriptor2];
[fetch setSortDescriptors:sortDescriptors];