CoreData sort on to-many relationship
Asked Answered
V

5

13

I'm writing an iOS app which has store of person records, and needs to display lists them sorted in particular ways. There are a variable number of these orderings, and they are generated on the fly, but I would like them to be stored in the datastore. The SQL way to do this is to have a ListPositions table with a list name, an id into the persons table, and a sort key. Then, to display a particular list, I can select all list ListPositions with a given name, pull in the referenced persons, and sort on the sort key. Trying to do this in CoreDatat, however I run into problems. I am trying to do this using a schema like:

Person:
    Name
    DOB
    etc... 
    positions -->> ListPosition

ListPosition:
    listName
    sortKey
    person --> Person

Then, I can get all the Persons in a given list with the NSPredicate [NSPredicate predicateWithFormat:@"ANY positions.listName like %@", someList]; This allows me to dynamically add lists against a large set of Persons. The problem is that I am unable to use the sortKey field of ListPosition to sort the Persons. What NSSortDescriptor will do this? And if it is not possible to sort a fetch on the property of one element of a to-many relationship, what is another way to get multiple, dynamic orderings in coredata? I am displaying the lists with a NSFetchedResultsController, so I can't put the lists together myself in memory. I need to do it with a single NSFetchRequest.

Vulgate answered 6/2, 2011 at 20:29 Comment(1)
some nicer formatting would it make much easier to read ur question.Lactobacillus
S
6

You're right-- following a to-many relationship returns an NSSet, which has no inherent sorting. To get sorted results there are a couple of options:

  1. Assuming that Person/ListPosition is a two-way relationship, do a new fetch request for ListPosition entities. Make the predicate match on the "person" relationship from ListPosition, which would look something like [NSPredicate predicateWithFormat:@"person=%@", myPerson]. Use whatever sort descriptor you need on the fetch request.
  2. Follow the relationship as you're doing, which gives you an NSSet. Then use NSSet's -sortedArrayUsingDescriptors: method to convert that to a sorted array.
Screwed answered 6/2, 2011 at 22:3 Comment(1)
I was not clear. My problem is not how to sort the objects in a to-many relationship, but rather how to provide many different sort orderings for a large set of objects. I've edited the question.Vulgate
R
1

I think the best approach in this case would be to fetch on ListPosition entity instead. Add the sort Descriptor for sortKey (it would work in this case because the fetch request is on ListPosition entity) and prefetch the Person associated with the the list name using setRelationshipKeyPathsForPrefetching for "person" on the fetch request.

[NSPredicate predicateWithFormat:@"listName like %@", someList];
Ria answered 13/9, 2012 at 5:13 Comment(1)
This works, however if you make any edits to the Person object it will not trigger NSFetchedResultsController to update as the ListPosition did not change.Corse
R
1

If I understand your model correctly, each Person has one ListPosition for each list in which it participates. Let's say we have acsending list by their names, so X people have X list positions with the same listName and sortKey.

I would create entity List, that would contain the sortKey attribute and then use it in sort descriptor.

entity List:
    - sortKey : string
    - ascending : bool

Create sort descriptor and use it in fetch request:

[NSSortDescriptor sortDescriptorWithKey:chosenList.sortKey ascending:chosenList.ascending];

Then you may have as many Lists as you want and you can easily use its sort key to sort all people.


If you want to store the positions in database (you didn't mention attribute index in your ListPosition, or anything similar), you can create “joint entity”:

entity PersonInList:
    - index : integer
    - person -> Person
    - list –> List

Another idea is having ordered set of Person objects directly in List entity.

Rupert answered 29/11, 2012 at 22:2 Comment(0)
T
1

Get the ListPosition (it will come as a NSMutableSet). Then do a sort on the Set, like this:

NSMutableSet *positionsSet = [personEntity mutableSetValueForKey:@"positions"];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"yourSortKey" ascending:NO];
NSArray *positionsSortedSet = [positionsSet sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];

That will give you a sorted out array according to your key.

Taffrail answered 18/12, 2013 at 22:11 Comment(0)
R
0

I usually add an index field (type NSNumber) to an entity. It's very easy to calculate index in adding item. just by

object.index = person.positions.count

so, actually you don't need positions field but positions relationship. connect person entity to ListPosition entity would be enough.

Resh answered 24/7, 2013 at 6:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.