Swift NSFetchRequest 按一个属性分组

Posted

技术标签:

【中文标题】Swift NSFetchRequest 按一个属性分组【英文标题】:Swift NSFetchRequest group by one attribute 【发布时间】:2015-11-13 18:26:59 【问题描述】:
    let fetchRequest = NSFetchRequest(entityName: "Product")
    fetchRequest.predicate = NSPredicate(format: "shopItem.wishList == %@", currentWishList)
    fetchRequest.resultType = .DictionaryResultType
    fetchRequest.sortDescriptors = [NSSortDescriptor(key: "mainBestPrice", ascending: true)]
    let minPriceExpression = NSExpression(format: "min:(mainBestPrice)")
    let minPriceED = NSExpressionDescription()
    minPriceED.expression = minPriceExpression
    minPriceED.name = "productPrice"
    minPriceED.expressionResultType = .DoubleAttributeType
    fetchRequest.propertiesToFetch = ["shopItem.keyword", "productTitle", minPriceED]
    fetchRequest.propertiesToGroupBy = ["shopItem.keyword"]

我想用NSFetchRequest按一个字段分组,但总是报错:

CoreData:错误:严重的应用程序错误。异常被捕获 在核心数据更改处理期间。这通常是一个错误 NSManagedObjectContextObjectsDidChangeNotification 的观察者。 带有 GROUP BY 组件的查询中的 SELECT 子句只能包含 在 GROUP BY 或聚合函数中命名的属性

我应该在分组中使用来自propertiesToFetch 的所有字段。但我不想这样做......

【问题讨论】:

没有办法解决这个问题。您必须将productTitle 添加到propertiesToGroupBy,或者将其从propertiesToFetch 中删除。可能你可以通过不同的方式获得你想要的东西:要么使用键值编码集合运算符,要么使用 NSFetchedResultsController。如果您编辑帖子以包含实体和关系的详细信息(一对多、多对多),我相信您会得到一些建议。 我真的需要所有字段,你能告诉我如何在fetchRequest 之后对结果进行分组吗? 【参考方案1】:

一种选择是使用NSFetchedResultsController(请参阅Apple Docs)。这通常用于填充表视图,但也可用于对 CoreData 提取的结果进行分组 - sectionNameKeyPath 确定分组。必须以确保组中的所有项目一起排序的方式对提取进行排序。在您的示例中,您按shopItem.keyword 分组,因此您需要将shopItem.keyword 指定为第一个排序描述符。第二个排序描述符应该是mainBestPrice(升序),因此每个组中的第一个项目是该组中mainBestPrice 最低的项目。因此,FRC 的配置如下所示:

let fetchRequest = NSFetchRequest(entityName: "Product")
fetchRequest.predicate = NSPredicate(format: "shopItem.wishList == %@", currentWishList)
let keyWordSort = NSSortDescriptor(key: "shopItem.keyword", ascending: true)
let priceSort = NSSortDescriptor(key: "mainBestPrice", ascending: true)
fetchRequest.sortDescriptors = [keyWordSort, priceSort];
let myFetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.managedObjectContext!, sectionNameKeyPath:"shopItem.keyword", cacheName:nil)
do 
    try myFetchedResultsController.performFetch()
 catch let error as NSError 
    // Replace this implementation with code to handle the error appropriately.
    print("Unresolved error \(error), \(error!.userInfo)")
    abort()

现在,最低最优价格的产品将成为每个部分的第一项,例如。对于第一部分(即第一个shopItem.keyword):

let firstProduct = myFetchedResultsController.sections![0].objects![0] as! Product

或获取它们的数组(对于所有shopItem.keywords),

let products = myFetchedResultsController.sections!.map()  $0.objects![0] as! Product

NSFetchedResultsController 将尽最大努力优化内存和速度,但如果你有大容量,你应该小心。

【讨论】:

以上是关于Swift NSFetchRequest 按一个属性分组的主要内容,如果未能解决你的问题,请参考以下文章

Swift 3 - NSFetchRequest 不同的结果

Swift - NSFetchRequest 错误

Swift 3. NSFetchRequest propertiesToFetch

NSFetchRequest 上的 Swift2.0 CoreData 问题

Swift Core Data NSFetchRequest 没有结果

Coredata NSFetchRequest DictionaryResultType 空属性 Swift