0

我正在使用 Core Data 来存储由值和时间戳组成的简单实体。我正在寻找一个获取请求,它返回最新添加的值,以及所有值的运行平均值。这一切似乎都很简单,直到我尝试使用 NSPredicate 将结果过滤到特定时间段内。

我正在使用 NSExpression 的expressionForFunction:withArguments:方法来确定平均值。通过设置启动标志-com.apple.CoreData.SQLDebug 1,我可以清楚地看到只有最新的值符合我的日期谓词。相反,平均计算是作为子查询执行的,但没有考虑我的日期谓词:

SELECT (SELECT avg(t1.ZVALUE) FROM ZEVENT t1 WHERE t1.Z_ENT = ?),  t0.ZVALUE FROM ZEVENT t0 WHERE ( t0.ZTIMESTAMP >= ? AND  t0.Z_ENT = ?) ORDER BY t0.ZTIMESTAMP DESC

在仍然尊重我的 NSFetchRequest 谓词的同时确定平均值的最有效(和可扩展)的方法是什么?

作为参考,这是我的完整代码:

NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timestamp" ascending:NO];

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Reading" inManagedObjectContext:moc];
[request setEntity:entity];
[request setSortDescriptors:@[sortDescriptor]];
[request setResultType:NSDictionaryResultType];

// Filter by date where necessary
NSPredicate *datePredicate = [NSPredicate predicateWithFormat:@"(timestamp >= %@)", toDate];
[request setPredicate:datePredicate];

NSExpression *valueExpression = [NSExpression expressionForKeyPath:valueKey];
NSExpressionDescription *valueDescription = [[NSExpressionDescription alloc] init];
[valueDescription setName:@"value"];
[valueDescription setExpression:valueExpression];
[valueDescription setExpressionResultType:NSDoubleAttributeType];

NSExpression *avgExpression = [NSExpression expressionForFunction:@"average:" arguments:[NSArray arrayWithObject:valueExpression]];
NSExpressionDescription *avgDescription = [[NSExpressionDescription alloc] init];
[avgDescription setName:@"averageReading"];
[avgDescription setExpression:avgExpression];
[avgDescription setExpressionResultType:NSDoubleAttributeType];

[request setPropertiesToFetch:@[avgDescription, valueDescription]];
4

1 回答 1

0

我看到两个错误。没有显示初始化toDate。我还注意到您正在传递setPropertiesToFetch:一个 NSExpressions 数组,但文档需要一个 NSPropertyDescriptions 数组。我希望当您执行 fetch 请求时,这种差异会导致 null 结果并填充 NSError。

你从中看到了什么结果executeFetchRequest:error:?请务必检查 NSError 结果。成语是这样的:

    NSError *error;
    NSArray *results = [context executeFetchRequest:fetchRequest error:&error];
    if (!results) {
        NSLog(@"%@ fetch error for request %@: %@ %@", fetchRequest,
              error.localizedDescription, error.localizedFailureReason);
    }

我会采取不同的方法。一个 fetch 请求的限制为 1,timestamp降序排序,并返回最新的timestamp. 如果您愿意,可以添加谓词以限制时间。然后使用第二个获取请求来计算时间戳的平均值。您甚至可以将这些调用封装到它们自己的方法中:

-(NSDate *)latestTimestamp:(NSManagedObjectContext *)moc;

-(NSNumber *)averageValueSinceTime:(NSDate *)intervalStart
                           context:(NSManagedObjectContext *)moc;
于 2012-12-29T00:08:30.430 回答