核心数据查询,每年最近的车?

时间:2017-11-16 03:03:29

标签: ios swift core-data

在我的模型中,我有一个Car实体。

汽车  年  CREATEDATE  名称

我想运行一个fetch,每年返回所有最近的汽车名称不是nil(名称可以是nil)。

所以,如果我拥有3辆车,2000年和5辆汽车,2010年,我想从获取请求中获得总共2辆汽车(2000年的最新车型和2010年的最新车型)。

我不确定如何编写正确的谓词来实现这一点。我查看了returnsDistinctResults选项,但我不确定这是正确的路径下去它还说它只适用于NSDictionaryResultType,这对我不起作用。

完成此操作的正确查询/谓词是什么?

2 个答案:

答案 0 :(得分: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无法轻松解决问题,最好只编写排序算法。

答案 1 :(得分:-1)

你可以实现这一点,如果说你将数年的数组传递给算法,并期望以字典的形式得到结果,每年你作为一个对应最多的对象的键传入那年的最近一辆车。

即:

let years : [Int] = [2000, 2005]


//The ideal method:

func mostRecentFor<T>(years: [Int]) -> [String:T]

假设您只使用少量搜索年,并且您的数据库拥有少量汽车,则不必担心线程问题。否则,对于这种方法,您必须使用并发或专用线程来获取,以避免阻塞主线程。出于测试目的,您不需要。

要实现此目的,您将使用沿着以下行的方法。

首先,应该像其他答案所建议的那样在年份上使用数字谓词。 为此,您将使用NSPredicate的日期格式:

NSPredicate(format: "date == %@", year)

因此,您的模型应将年份作为参数,将实际的nsdate作为另一个参数。然后,您可以将fecthLimit参数设置为1,并将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 struct对应物可以使从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