Chained expressions to perform calculations in Core Data

前端 未结 1 1541
走了就别回头了
走了就别回头了 2020-12-05 22:39

First of all: Happy new year :-)

What I am trying to do

I am trying to divide two attributes in Core Data and then calculate the average of these divisions.

相关标签:
1条回答
  • 2020-12-05 22:44

    It seems that "collection" function expressions like @average can only be used with key paths, but not in combination with other general expressions, when used as propertiesToFetch. I do not have a reference for that, but it is a problem that others have noticed also:

    • Fetch aggregate data from NSManagedObject using another expression as argument to sum: expression
    • Performing multiplication (aggregation) with CoreData: how to?

    So you could proceed in two steps: First execute a fetch request that returns an array with the results of all divisions:

    NSExpression *fromCurrencyPathExpression = [NSExpression
                                                expressionForKeyPath:@"eur"];
    NSExpression *toCurrencyPathExpression   = [NSExpression
                                                expressionForKeyPath:@"usd"];
    NSExpression *divisionExpression = [NSExpression
                                        expressionForFunction:@"divide:by:"
                                        arguments:@[fromCurrencyPathExpression,
                                        toCurrencyPathExpression]];
    
    NSString *expressionName = @"ratio";
    NSExpressionDescription *expressionDescription =
    [[NSExpressionDescription alloc] init];
    expressionDescription.name = expressionName;
    expressionDescription.expression = divisionExpression;
    expressionDescription.expressionResultType= NSDoubleAttributeType;
    
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Entity"];
    
    request.propertiesToFetch = @[expressionDescription];
    request.resultType = NSDictionaryResultType;
    
    NSError *error;
    NSArray *ratios = [context executeFetchRequest:request error:&error];
    

    The result is an array of dictionaries:

    (lldb) po ratios
    (NSArray *) $0 = 0x00000001001170f0 <_PFArray 0x1001170f0>(
    {
        ratio = "0.5454545454545454";
    },
    {
        ratio = "0.4";
    },
    {
        ratio = "0.5";
    }
    )
    

    Also, with the "-com.apple.CoreData.SQLDebug 1" option one can see that the divisions are already executed on the SQLite level:

    sql: SELECT  t0.ZEUR /  t0.ZUSD FROM ZENTITY t0
    

    Then you can compute the average of all ratios in memory, using Key-Value Coding:

    NSNumber *average = [ratios valueForKeyPath:@"@avg.ratio"];
    

    and the result is

    (lldb) po average
    (NSNumber *) $0 = 0x000000010012fd60 0.4818181818181818
    
    0 讨论(0)
提交回复
热议问题