Group by one property, getting more data with master data

I have a table in Core Data with the following properties:

date, name, phone 

I want to get a list of 5 unique phone numbers with names sorted by date. Therefore, in MySQL it will be something like this:

 SELECT name, phone FROM myTable GROUP BY phone ORDER BY date 

So, if I have this data list:

 01/23/2015 someName1 12345678 01/21/2015 someName2 12345678 01/21/2015 someOtherName1 987654321 

I would like to get a list of unique phone numbers with a date field that determines which name should be associated with any duplicate numbers. In this case, the desired result would be:

 01/23/2015 someName1 12345678 01/21/2015 someOtherName1 987654321 

However, doing this with NSFetchRequest seems a bit complicated, as setPropertiesToGroupBy requires you to contain the same list of properties as setPropertiesToFetch .

In other words, I would think that I could do this:

  NSEntityDescription *entity = [NSEntityDescription entityForName:@"someEntity" inManagedObjectContext:someContext]; NSFetchRequest *request = [[NSFetchRequest alloc] init]; [request setEntity:entity]; [request setResultType:NSDictionaryResultType]; [request setPropertiesToFetch:@[@"name", @"phone"]]; [request setPropertiesToGroupBy:@[@"phone"]]; [request setFetchLimit:5]; NSSortDescriptor *sortByCreatedDate = [[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO]; [request setSortDescriptors:@[sortByCreatedDate]]; 

However, I will get an exception in propertiesToGroupBy if I do not include the name field.

How can I achieve what I want without manually navigating the list?

+5
source share
1 answer

Provided that I think this will work; I leave it to you to check it to death:

You cannot add any other attributes to propertiesToFetch other than those specified in propertiesToGroupBy , but it looks like you can include objectID in the properties to retrieve. To do this, create an NSExpression and its associated NSExpressionDescription for the "evaluated object":

 NSExpression *selfExp = [NSExpression expressionForEvaluatedObject]; NSExpressionDescription *selfED = [[NSExpressionDescription alloc] init]; selfED.name = @"objID"; selfED.expression = selfExp; selfED.expressionResultType = NSObjectIDAttributeType; 

Now define another expression / description to get max (date):

 NSExpression *maxDate = [NSExpression expressionForKeyPath:@"date"]; NSExpression *indexExp = [NSExpression expressionForFunction:@"max:" arguments:@[maxDate]]; NSExpressionDescription *maxED = [[NSExpressionDescription alloc] init]; maxED.name = @"maxDate"; maxED.expression = indexExp; maxED.expressionResultType = NSDateAttributeType; 

Then include these two expression descriptions in the property list to retrieve:

 [request setPropertiesToFetch:@[@"phone", maxED, selfED]]; [request setPropertiesToGroupBy:@[@"phone"]]; 

When you start the selection, each element in the resulting array will have the key "objID" containing the identifier of the object for the corresponding object. You can unzip this to access the name, phone, etc., with something like this:

 NSArray *results = [self.context executeFetchRequest:request error:&error]; for (NSDictionary *dict in results) { NSDate *maxDate = dict[@"maxDate"]; NSString *phone = dict[@"phone"]; NSManagedObjectID *objID = [dict valueForKey:@"objID"]; NSManagedObject *object = [self.context objectWithID:objID]; NSString *name = [object valueForKey:@"name"]; } 

One specific aspect that I'm not sure about is how it will look if two strings have exactly the same date .

+4
source

Source: https://habr.com/ru/post/1211872/


All Articles