0
votes

I'm trying to sort by an aggregate function in Core Data. I've a model that has entities Recipe and Food, with a relationship of many-to-many between them. I start with a query that lists recipes that contain foods I've listed. Thus far I've got:

NSExpression* key_path_exp = [NSExpression expressionForKeyPath:@"recipeName"];
NSExpression *countExpression =  [NSExpression expressionForFunction: @"count:"
                                                           arguments: [NSArray arrayWithObject:key_path_exp] ];

// Count the number of specified foods that this recipe contains, by counting the grouped by recipeName
NSExpressionDescription *count_description = [[NSExpressionDescription alloc] init];
[count_description setName: @"count"];
[count_description setExpression: countExpression];
[count_description setExpressionResultType: NSInteger32AttributeType];

// Which of the columns I'm interested in
NSAttributeDescription* recipe_name_column = [_fetchRequest.entity.attributesByName objectForKey:@"recipeName"];
[_fetchRequest setPropertiesToFetch:[NSArray arrayWithObjects:recipe_name_column, count_description,  nil]];
// Group by the recipe name
[_fetchRequest setPropertiesToGroupBy:[NSArray arrayWithObject:recipe_name_column]];

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ANY %K IN %@",@"foods",foods];
[_fetchRequest predicate];
// Required for group by
[_fetchRequest setResultType:NSDictionaryResultType];

NSSortDescriptor* sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"healthFactor" ascending:NO];
[_fetchRequest setSortDescriptors:@[sortDescriptor]];

NSError *error = nil;
if (![_fetchedResultsController performFetch:&error])
{
    // Update to handle the error appropriately.
    NSLog(@"Unresolved error %@, %@", error.localizedDescription, [error userInfo]);
    exit(-1);  // Fail
}

Which produces the SQL:

SELECT t0.ZRECIPENAME, COUNT( t0.ZRECIPENAME) FROM ZRECIPE t0 GROUP BY  t0.ZRECIPENAME ORDER BY t0.ZHEALTHFACTOR DESC

And an example of output:

Old-school venison pie with juniper, rosemary & bay|5
Oriental pork with noodles|7
Pad Thai|3
Pint of prawns|10
Potato Gnocchi|7
Pumpkin Flan Recipe|12

When connecting directly to the sqlite database I can edit the query such that the ORDER BY becomes:

ORDER BY count(t0.ZRECIPENAME) ASC

which produces exactly the results I'm after. But, how can this be implemented in core data using NSSortDescriptor?

Can anyone suggest a way of sorting against the result set before models are created? NSSortDescriptior will only let me sort by any one of the Entity's keys. Or perhaps there's more efficient sorting solution other than sorting against the NSDictionary results. The result sets can be 1000's of rows. Thanks!

1

1 Answers

0
votes

Try using the convenience method sortUsingComparator...

    [<<insert Array or Dictionary>> sortUsingComparator:^NSComparisonResult(ObjectA *objectA, ObjectB *objectB) {
        NSString *titleA = nil;
        NSString *titleB = nil;

        titleA = [objectA valueForKey:@"titleForObjectA"];
        titleB = [objectB valueForKey:@"titleForObjectB"];

        return [titleA localizedStandardCompare:titleB];
    }];

UPDATE: apologies this is a convenience method for NSMutableArray.

Although there is a similar method for an NSDictionary...

keysSortedByValueUsingComparator documentation here, so maybe you can add a comparator block similar to the above into this convenience method?