0
votes

I need to transfer SQL query in Core Data:

SELECT `quadkey`, MIN(id) AS id, COUNT(id) AS count, AVG(longitude) AS longitude, AVG(latitude) AS latitude
FROM marker 
GROUP BY (quadkey & 15499683151872);

my code:

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"GBUserRoute"];
NSExpressionDescription *countExpressionDescription = [self expressionForFunction:@"count:" arguments:@[[NSExpression expressionForKeyPath:@"routeId"]] resultName:@"count" resultType:NSDoubleAttributeType];

NSExpressionDescription *minIdExpressionDescription = [self expressionForFunction:@"min:" arguments:@[[NSExpression expressionForKeyPath:@"routeId"]] resultName:@"minId" resultType:NSDoubleAttributeType];

NSExpressionDescription *averageLatitudeExpressionDescription = [self expressionForFunction:@"average:" arguments:@[[NSExpression expressionForKeyPath:@"latitude"]] resultName:@"latitude" resultType:NSDoubleAttributeType];

NSExpressionDescription *averageLongitudeExpressionDescription = [self expressionForFunction:@"average:" arguments:@[[NSExpression expressionForKeyPath:@"longitude"]] resultName:@"longitude" resultType:NSDoubleAttributeType];

NSExpressionDescription *minLongitudeExpressionDescription = [self expressionForFunction:@"min:" arguments:@[[NSExpression expressionForKeyPath:@"longitude"]] resultName:@"minLongitude" resultType:NSDoubleAttributeType];

NSExpressionDescription *minLatitudeExpressionDescription = [self expressionForFunction:@"min:" arguments:@[[NSExpression expressionForKeyPath:@"latitude"]] resultName:@"minLatitude" resultType:NSDoubleAttributeType];

NSExpressionDescription *maxLongitudeExpressionDescription = [self expressionForFunction:@"max:" arguments:@[[NSExpression expressionForKeyPath:@"longitude"]] resultName:@"maxLongitude" resultType:NSDoubleAttributeType];

NSExpressionDescription *maxLatitudeExpressionDescription = [self expressionForFunction:@"max:" arguments:@[[NSExpression expressionForKeyPath:@"latitude"]] resultName:@"maxLatitude" resultType:NSDoubleAttributeType];

NSExpressionDescription *groupExpressionDescription = [self expressionForFunction:@"bitwiseAnd:with:" arguments:@[[NSExpression expressionForKeyPath:@"quadKey"], [NSExpression expressionForConstantValue:@(15499683151872)]] resultName:@"quadKeyMask" resultType:NSInteger64AttributeType];

[fetchRequest setPropertiesToFetch:@[groupExpressionDescription, countExpressionDescription, minIdExpressionDescription, averageLongitudeExpressionDescription, averageLatitudeExpressionDescription, minLongitudeExpressionDescription, minLatitudeExpressionDescription, maxLongitudeExpressionDescription, maxLatitudeExpressionDescription]];
[fetchRequest setPropertiesToGroupBy:@[groupExpressionDescription]];
[fetchRequest setResultType:NSDictionaryResultType];

+ (NSExpressionDescription *)expressionForFunction:(NSString *)function arguments:(NSArray<NSExpression *> *)arguments resultName:(NSString *)resultName resultType:(NSAttributeType)resultType {
NSExpression *expression = [NSExpression expressionForFunction: function
                                                                arguments: arguments];
    NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
    [expressionDescription setName: resultName];
    [expressionDescription setExpression: expression];
    [expressionDescription setExpressionResultType: resultType];

    return expressionDescription;
}

When running this code, I get the following error:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid keypath expression ((), name quadKeyMask, isOptional 1, isTransient 0, entity (null), renamingIdentifier quadKeyMask, validation predicates ( ), warnings ( ), versionHashModifier (null) userInfo { }) passed to setPropertiesToFetch:'

1
Core data is not an SQL database. It is an object persistence system that may use SQLite as the object store.Paulw11

1 Answers

0
votes

First, without seeing your data model we cannot actually help you debug your query.

Your error:

Invalid keypath expression ((), name quadKeyMask, isOptional 1, isTransient 0, entity (null), renamingIdentifier quadKeyMask, validation predicates ( ), warnings ( ), versionHashModifier (null) userInfo { }) passed to setPropertiesToFetch:

indicates that the key path interpreter cannot follow your data model. IOW, you have an error in your entity or expression.

The key to rewriting SQL queries in Core Data is to understand that they are very different languages. Core Data predicates are set selection operations using filter criteria. While this appears to be similar to a SQL declarative language, it is different. The conceptual models are different.

My advice: Rewrite your query in small pieces. Just as you would to debug any other problem. Make the small pieces work; then make small combinations of your expressions work. Divide and conquer.