NSFetchRequest:查询不同的值并计算其他属性值

Posted

技术标签:

【中文标题】NSFetchRequest:查询不同的值并计算其他属性值【英文标题】:NSFetchRequest: Query for distinct values and count other properties values 【发布时间】:2015-08-29 10:16:55 【问题描述】:

我尝试为实体Location 设置NSFetchRequest,其属性类似于countrycity

country  | city
————————————————
Germany  | Berlin
USA      | San Francisco
USA      | New York
Germany  | Munich
Germany  | Munich
USA      | San Francisco
Germany  | Stuttgart

NSFetchRequest 应返回国家/地区(或具有相应国家/地区的 Location 对象)和城市数量。

[
     country: 'Germany', cityCount: 3 ,
     country: 'USA', cityCount: 2 
]

我知道我可以获取所有条目并“自己计算”,但我对如何设置适当的获取请求(或者如果可以这样做)很感兴趣,并且想看看你会怎么做! :)

【问题讨论】:

这当然是可能的。你使用的是 Swift 还是 Objective-C? 我更喜欢 Swift 而不是 Obj-C 但我可以同时阅读 ;) 我说得太早了;实现“distinct”要求的同时还使用“group by”进行计数并不容易。也许这就是你问的原因。 【参考方案1】:

这个问题的正确答案是重构数据模型避免冗余

国家/地区字符串在表中不必要地重复。此外,您无缘无故地使一个简单的查询变得复杂。该模型应该反映您的数据,而为每个美国城市写出“美国”既不聪明也不高效。

你的数据模型应该是这样的

Country <----->> City

现在您可以通过cities.count 获取所有国家/地区并获取城市。

【讨论】:

我喜欢使用这种方法......但有时你没有这个机会;)【参考方案2】:

为了实现(我认为)你想要的,我不得不求助于两个单独的提取。对于countrycity 的每个不同组合,第一次获取获取一个对象的objectID。使用IN 谓词过滤第二次提取,仅针对这些对象。它使用NSExpressionpropertiesToGroupBy 来获取每个country 的计数:

    // Step 1, get the object IDs for one object for each distinct country and city 
    var objIDExp = NSExpression(expressionType: NSExpressionType.EvaluatedObjectExpressionType)
    var objIDED = NSExpressionDescription()
    objIDED.expression = objIDExp
    objIDED.expressionResultType = .ObjectIDAttributeType
    objIDED.name = "objID"
    var fetch = NSFetchRequest(entityName: "Location")
    fetch.propertiesToFetch = [objIDED]
    fetch.propertiesToGroupBy = ["country", "city"]
    fetch.resultType = .DictionaryResultType
    let results = self.managedObjectContext!.executeFetchRequest(fetch, error: nil)

    // extract the objectIDs into an array...
    let objIDArray = (results! as NSArray).valueForKey("objID") as! [NSManagedObjectID];

    // Step 2, count using GROUP BY
    var countExp = NSExpression(format: "count:(SELF)")
    var countED = NSExpressionDescription()
    countED.expression = countExp
    countED.expressionResultType = .ObjectIDAttributeType
    countED.name = "count"
    var newFetch = NSFetchRequest(entityName: "Location")
    newFetch.predicate = NSPredicate(format: "SELF IN %@", objIDArray)
    newFetch.propertiesToFetch = ["country", countED]
    newFetch.propertiesToGroupBy = ["country"]
    newFetch.resultType = .DictionaryResultType
    let newResults = self.managedObjectContext!.executeFetchRequest(newFetch, error: nil)
    println("\(newResults!)")

这将是低效的:如果您有大量不同的国家和城市,IN 谓词会减慢速度。您可能会发现获取所有内容并计算它们的效率更高。

【讨论】:

我以前从未使用过 IN 谓词,这确实是一个很酷的方法。我希望它可以在一个 NSFetchRequest... 中实现。如果下周没有其他解决方案,我会接受你的回答!非常感谢您! :) 这个解决方案比使用 KVC 在内存中获取和解析更长且效率更低。

以上是关于NSFetchRequest:查询不同的值并计算其他属性值的主要内容,如果未能解决你的问题,请参考以下文章

子查询 django 查询以从对象中获取最大的不同值并返回这些对象

如何将来自不同查询的值(计数)组合成一个查询

SQL如果为true,则查看不同的列值并对其进行计数

获取元素的值并使其成为 XSLT 中属性的值?

Swift 计算 UITextFields 的值并返回值

比较两个表中的值并计算它们的差异