Pius
Pius

Reputation: 125

Filtering a relationship of an NSManagedObject

Suppose a Manager has a to-many relationship with Employee objects. Given a reference to a Manager object (i.e. NSManagedObject *manager), how do I get a reference to "the Employee with the lowest salary among all of those whose salaries exceed 10000"?

I can think of two possible approaches:

Approach 1: constructing an NSFetchRequest and specifying the Manager wanted with the object ID of the Manager in question.

Approach 2: some kind of key-value coding expression on Manager, e.g. [manager valueForKeyPath:@"..."] (with some use of NSPredicate?)

I'm inclined towards Approach 2 if there's a plausible solution. Please enlighten me.

Upvotes: 2

Views: 1778

Answers (2)

Jody Hagins
Jody Hagins

Reputation: 28409

Of course, you can just apply a predicate and sort descriptor to the set returned by the relationship. Easy, and pretty quick if the set is relatively small (because it is done in memory, all the objects will have to be fetched). You may want to do that batch fetch up front to limit the number of times you do I/O.

Depending on the size of the database and the number of employees under the manager (and the indexing), you may want to do it all at the database level...

// We want "Employee" objects
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];
// Assuming the "inverse" relationship from employee-to-manager is "manager"...
// We want all employees that have "our" manager, and a salary > 10000
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"(manager == %@) AND (salary > 10000", manager];
// Sort all the matches by salary, little-to-big
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"salary" ascending:YES]];
// Limit the returned set to 1 object, which will be the smallest
fetchRequest.fetchLimit = 1;

This will perform the entire query at the database level, and only return 1 object.

As always, performance issues are usually highly dependent on your model layout, and the options used for specifying the model and its relationships.

Upvotes: 3

Nikita Pestrov
Nikita Pestrov

Reputation: 5966

You can filter your array of Employee relationship to get the one you want. 1) First, get all the Employee with salaries over 10000:

NSArray *filtered = [manager.employees filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"(salary > 10000)"]];

2)Then sort it in descending order

NSSortDescriptor* sortOrder = [NSSortDescriptor sortDescriptorWithKey: @"salary" ascending: NO];
NSArray *sortedAndFiltered =  [filtered sortedArrayUsingDescriptors: [NSArray arrayWithObject: sortOrder]];

3)Then just get your employee

[sortedAndFiltered lastObject];

Upvotes: 1

Related Questions