核心数据查询,每年最近的汽车?
Posted
技术标签:
【中文标题】核心数据查询,每年最近的汽车?【英文标题】:Core Data Query, most recent car per year? 【发布时间】:2017-11-16 03:03:28 【问题描述】:在我的模型中,我有一个 Car 实体。
汽车 年 创建日期 名字
我想运行一个 fetch 来返回每年所有最近的汽车,其中 name 不是 nil(name 可以是 nil)。
因此,如果我有 3 辆 2000 年的汽车和 5 辆 2010 年的汽车,我想从获取请求中总共获得 2 辆汽车(最近的是 2000 年,最近的是 2010 年)。
我不确定如何编写正确的谓词来实现这一点。我查看了 returnDistinctResults 选项,但我不确定这是正确的路径,它还说它只适用于对我不起作用的 NSDictionaryResultType。
完成这项工作的正确查询/谓词是什么?
【问题讨论】:
【参考方案1】:您最好使用算法简单地遍历每条记录。
允许您的 Car 类,定义以下内容。
struct C
var year: Int
var created: Date
var name: String?
var cars = [C(year: 2009, created: Date(), name: nil), C(year: 2009, created: Date(), name: "Green"), C(year: 2010, created: Date(), name: "Green"), C(year: 2010, created: Date(), name: "Orange"), C(year: 2010, created: Date(), name: "Orange")]
var carsPerYear = [Int: [String: Int]]()
for car in cars
if let name = car.name
var info: [String: Int]? = nil
if carsPerYear.keys.contains(car.year)
info = carsPerYear[car.year]
else
info = [String: Int]()
if !info!.keys.contains(name)
info![name] = 0
info![name] = info![name]! + 1
carsPerYear[car.year] = info
for year in carsPerYear.keys
let info = carsPerYear[year]!
let sorted = info.keys.sorted info[$0]! > info[$1]!
print(year, sorted.first!)
给出输出
2009 Green
2010 Orange
有时SQL或CoreData不能轻易解决问题,最好只写排序算法。
【讨论】:
【参考方案2】:您可以实现这一点,假设您将一个年份数组传递给一个算法,并期望以字典的形式得到一个结果,每一年您作为一个对象的键传入,该对象对应于最那年最近的车。
即:
let years : [Int] = [2000, 2005]
//The ideal method:
func mostRecentFor<T>(years: [Int]) -> [String:T]
假设您只使用少量搜索年份,并且您的数据库中有少量汽车,您不必担心线程问题。否则,对于这种方法,您必须使用并发或专用线程进行提取以避免阻塞主线程。出于测试目的,您不需要这样做。
要做到这一点,您可以使用以下方法。
首先,应该像其他答案所建议的那样在年份上使用数字谓词。 为此,您将使用 NSPredicate 的日期格式:
NSPredicate(format: "date == %@", year)
因此,您的模型应该将年份作为参数,将实际的 nsdate 作为另一个参数。然后,您将使用设置为 1 的 fecthLimit
参数,并将 sortDescriptor
应用于 nsDate 键参数。后两者的组合将确保只返回给定年份的最年轻或最旧的值。
func mostRecentFor(years: [Int]) -> [String:Car]
let result : [String:Car] = [:]
for year in years
let request: NSFetchRequest<CarModel> = CarModel.fetchRequest()
request.predicate = NSPredicate(format: "date == %@ AND name != nil", year)
request.fetchLimit = 1
let NSDateDescriptor: let sectionSortDescriptor = NSSortDescriptor(key: "nsDate", ascending: true)
let descriptors = [NSDateDescriptor]
fetchRequest.sortDescriptors = descriptors
do
let fetched = try self.managedObjectContext.fetch(request) as
[CarModel]
guard !fetched.isEmpty, fetched.count == 1 else
print("No Car For year: \(year)")
return
result["\(year)"] = new[0].resultingCarStruct //custom parameter here.. see bellow
catch let err
print("Error for Year: \(year), \(err.localizedDescription)")
return result
我们在这里使用升序设置为true
,因为我们希望第一个值,即由于fetchLimit
值为1而实际返回的值,是该年份最早的汽车,或者是最小的汽车nsDate 键的时间戳。
这应该为您提供一个用于小型数据存储和测试的简单获取查询。此外,创建一个方法或参数来将 CarModel 解释为其对应的 Car 结构体可以更简单地从 CD 转到内存对象。
所以你会像这样搜索你的汽车:
let years = [1985, 1999, 2005]
let cars = mostRecentFor(years: years)
// cars = ["1985": Car<year: 1985, name: "Chevrolet", nsDate: "April 5th 1985">, "1999" : Car<year: 1999, name: "Toyota Corolla", nsDate: "February 5th 1999">]
// This examples suggests that no cars were found for 2005
【讨论】:
我明白你的意思,这有三个问题: 1. 这种方法需要大量的磁盘,非常非常慢。 2.这个问题不是要求通过一系列年份,我只是想要每年最近的汽车 3.这个答案没有考虑名称!= nil 条件。谢谢。 1:我指定此方法适用于测试/小型数据库,并且您需要将其调整为并发包装器以获取更多信息。 2:“每年”可以表示从一组年份到两个给定年份之间的每一年的任何内容,这至少会导致一个年份数组(或在这种情况下为整数)。 3:确实我忘记了名字,检查 nil 是通过在谓词字符串中添加一个 AND 运算符来完成的,然后在字符串中或使用参数符号添加该避免的值。生病更新 这没有提供问题所要求的答案。对不起。 您的问题是询问查询中指定的每年最早的汽车,其名称没有零? “核心数据查询”,而不是“核心数据查询”。一个查询得到我想要的。您提供的内容在我可能传入的每一年都会进入磁盘。另外,正如我上面所说,我没有指定我想在几年内传递。那是您在此处添加的内容...所以,再次抱歉,但您的回答并未解决问题。谢谢以上是关于核心数据查询,每年最近的汽车?的主要内容,如果未能解决你的问题,请参考以下文章