HyLian
HyLian

Reputation: 5093

Grab firsts distinct entities ordered by datetime using Core Data

What I have

Message Entity

user  | text                          | date 
---------------------------------------------- 
user1 | This is first message user 1  | 10:50     **
user2 | This is first message user 2  | 10:50     **
user3 | This is first message user 3  | 10:50     **
user1 | This is second message user 1 | 10:00
user4 | This is first message user 4  | 10:00     **
user2 | This is second message user 2 | 10:00
user3 | This is second message user 3 | 10:00
user1 | This is third message user 1  | 9:00
...

With that data I want to grab the first message of each distinct user using CoreData in a single fetch request.

That is

user1|This is the first message user 1|10:50
user2|This is the first message user 2|10:50
user3|This is the first message user 3|10:50
user4|This is the first message user 4|10:00

You can achieve that by grabbing first the distinct users, and then, perform a fetch request for each user using a predicate, but it will end with a lot of "queries" (5 in this case). It would be nice if it can be done in a single request.

Thanks!

Upvotes: 1

Views: 92

Answers (2)

Jeff Wolski
Jeff Wolski

Reputation: 6372

There's an easier way. Do a fetch request of the user fields. This will produce a set containing each distinct user.

Next, enumerate through the set:

for (NSManagedObject *obj in fetchController.fetchedObjects){

}

Inside this loop, you can do another fetch using the obj object for the predicate. Sort by date wiht a maximum return of 1. The resulting set will be one object which is the first message for that user.

Upvotes: 0

Robin Summerhill
Robin Summerhill

Reputation: 13675

I would add a relationship to your user entity called something like 'lastMessage' which you will always keep up-to-date whenever you insert a new message. Then the problem becomes trivial.

In my experience it's easier to de-normalize your schema slightly to improve performance rather than trying to create really complex queries.

EDIT to show entities:

------------- 1  R1     * ------------
|User Entity|<----------->| Message  |
-------------             ------------
| name      |------------>| text     |
-------------    R2     1 | date     |
                          ------------

You have two entities - User and Message. Set up 2 relationships between the entities:

R1 - 'messages' bidirectional one-to-many (one user has many messages and one message belongs to one user)

R2 - 'lastMessage' unidirectional one-to-one (one user has one last message)

Keep R2 up-to-date whenever you add a new message.

To get last messages for all users perform a fetch request for all users and then just look at the R2 relationship.

Use setPropertiesToFetch: on the NSFetchRequest to populate the R2 relationship in a single trip to the database.

Upvotes: 2

Related Questions