如何配置NSFetchRequest获取通话用户时长汇总结果?
给定的Calls表
+--------+--------+----------+ | caller | callee | duration | +--------+--------+----------+ | A | B | 3 | | B | C | 1 | | C | A | 2 | | B | A | 5 | +--------+--------+----------+
期望输出
+------------+-------+ | subscriber | total | +------------+-------+ | A | 10 | | B | 9 | | C | 3 | +------------+-------+
好的,要通过NSFetchRequest实现这个需求,核心是要把每个用户作为主叫和被叫的通话时长分别求和,再合并得到总时长。因为Core Data的NSFetchRequest本身不支持直接将两个字段(caller和callee)作为同一分组维度,所以我们需要分两步获取数据,再合并结果。
下面是具体的实现步骤和代码:
步骤1:分别获取主叫和被叫的时长总和
首先创建两个NSFetchRequest,分别计算每个用户作为主叫、被叫的总时长:
// 获取主叫的总时长 NSFetchRequest *callerFetch = [NSFetchRequest fetchRequestWithEntityName:@"Calls"]; callerFetch.resultType = NSDictionaryResultType; // 定义求和表达式:计算每个caller的duration总和 NSExpression *sumCallerDuration = [NSExpression expressionForFunction:@"sum:" arguments:@[[NSExpression expressionForKeyPath:@"duration"]]]; NSExpressionDescription *callerTotalDesc = [NSExpressionDescription new]; callerTotalDesc.name = @"callerTotal"; callerTotalDesc.expression = sumCallerDuration; callerTotalDesc.expressionResultType = NSInteger32AttributeType; // 设置分组和要获取的属性 callerFetch.propertiesToGroupBy = @[@"caller"]; callerFetch.propertiesToFetch = @[@"caller", callerTotalDesc]; // 执行请求(假设已获取managedContext) NSError *error = nil; NSArray *callerResults = [managedContext executeFetchRequest:callerFetch error:&error]; if (error) { // 错误处理逻辑 } // 同理,获取被叫的总时长 NSFetchRequest *calleeFetch = [NSFetchRequest fetchRequestWithEntityName:@"Calls"]; calleeFetch.resultType = NSDictionaryResultType; NSExpression *sumCalleeDuration = [NSExpression expressionForFunction:@"sum:" arguments:@[[NSExpression expressionForKeyPath:@"duration"]]]; NSExpressionDescription *calleeTotalDesc = [NSExpressionDescription new]; calleeTotalDesc.name = @"calleeTotal"; calleeTotalDesc.expression = sumCalleeDuration; calleeTotalDesc.expressionResultType = NSInteger32AttributeType; calleeFetch.propertiesToGroupBy = @[@"callee"]; calleeFetch.propertiesToFetch = @[@"callee", calleeTotalDesc]; NSArray *calleeResults = [managedContext executeFetchRequest:calleeFetch error:&error]; if (error) { // 错误处理逻辑 }
步骤2:合并结果集,计算总时长
把主叫和被叫的结果合并,对每个用户的两个时长求和:
// 用字典临时存储每个用户的总时长 NSMutableDictionary *totalDurationDict = [NSMutableDictionary dictionary]; // 先处理主叫数据 for (NSDictionary *dict in callerResults) { NSString *subscriber = dict[@"caller"]; NSNumber *total = dict[@"callerTotal"]; totalDurationDict[subscriber] = total; } // 再处理被叫数据,和已有值相加 for (NSDictionary *dict in calleeResults) { NSString *subscriber = dict[@"callee"]; NSNumber *calleeTotal = dict[@"calleeTotal"]; if (totalDurationDict[subscriber]) { NSNumber *currentTotal = totalDurationDict[subscriber]; totalDurationDict[subscriber] = @([currentTotal integerValue] + [calleeTotal integerValue]); } else { totalDurationDict[subscriber] = calleeTotal; } } // 转换成期望的数组格式 NSMutableArray *finalResults = [NSMutableArray array]; for (NSString *subscriber in totalDurationDict.allKeys) { NSNumber *total = totalDurationDict[subscriber]; [finalResults addObject:@{@"subscriber": subscriber, @"total": total}]; } // 可选:按用户名排序 NSSortDescriptor *sortByName = [NSSortDescriptor sortDescriptorWithKey:@"subscriber" ascending:YES]; finalResults = [[finalResults sortedArrayUsingDescriptors:@[sortByName]] mutableCopy];
关键说明
- 使用
NSDictionaryResultType让Core Data返回字典格式的聚合结果,避免加载完整实体对象,提升效率。 NSExpressionDescription用于定义聚合函数(这里是sum:),实现分组求和的逻辑。- 合并时需处理“只作为主叫”或“只作为被叫”的用户,确保数据不遗漏。
这样处理后,finalResults的结构就和你期望的输出完全一致了。
内容的提问来源于stack exchange,提问作者Somebody
相关产品推荐
相关产品推荐

