You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何配置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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:19:13