NSFetchRequest两列和总和

时间:2018-03-16 10:56:31

标签: core-data nspredicate 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以获得所需的输出?

1 个答案:

答案 0 :(得分:0)

我必须以某种方式解决它(下面的代码不是我应用程序中的实际代码,而是草图)。它是一种“混合”解决方案,介于仅提取(我怀疑是可能的,CoreData缺少联合)和完整的内存之间。

class Subscriber:NSObject {

@objc dynamic var subscriber = 0
@objc dynamic var total = 0

init(dictionary: NSDictionary) {
    if let s = dictionary["caller"] as? Int { subscriber = s} 
    if let t = dictionary["total"] as? Int { total = t }
    super.init()
}

init(dictionary: NSDictionary, _:Bool) {
    if let s = dictionary["callee"] as? Int { subscriber = s} 
    if let t = dictionary["total"] as? Int { total = t }
    super.init()
}

在do ... catch:

中获取一个Subscriber对象数组
let req_a = NSFetchRequest<NSDictionary>(entityName:"Call")

let durExp = NSExpression(forKeyPath: "duration")

let sumDesc = NSExpressionDescription()
sumDesc.expression = NSExpression(forFunction: "sum:", arguments: [durExp])
sumDesc.name = "total"
sumDesc.expressionResultType = .integer64AttributeType

req_a.propertiesToGroupBy = ["caller"]
req_a.propertiesToFetch = ["caller", sumDesc]
req_a.resultType = .dictionaryResultType       

let req_b = NSFetchRequest<NSDictionary>(entityName:"Call")

req_b.propertiesToGroupBy = ["callee"]
req_b.propertiesToFetch = ["callee", sumDesc]
req_b.resultType = .dictionaryResultType

var subscriberResults_a = try theMOC.fetch(req_a).map { return Subscriber(dictionary: $0) }
var subscriberResults_b = try theMOC.fetch(req_b).map { return Subscriber(dictionary: $0, true) }

/// Add values from duplicates
subscriberResults_a = subscriberResults_a?.map { a -> Subscriber in
     guard let b = subscriberResults_b?.first(where: { $0.subscriber == a.subscriber }) else { return a }
     a.total += b.total
     return a
}

/// Filter out duplicates
subscriberResults_b = subscriberResults_b?.filter({ b -> Bool in
     if let found = subscriberResults_a?.contains (where: { $0.subscriber == b.subscriber }) { return !found }
     return true
})

subscriberArray = subscriberResults_a! +  subscriberResults_b!

仍在寻找更好的解决方案。