我有带有日期字段的记录:
class SomeRealmObject: Object {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var date: Date
... //some other properties
}
目标是计算按日期不同的记录计数(“不同”应忽略日期内的时间)。
如果我已经有了一个记录列表,我可以像通常的数组元素一样使用它们:
let allObjects = getAll() //SomeRealmObject array
let dates = allObjects.map { $0.startOfDay() }.reduce([]) { partialResult, date in
partialResult.contains(date) ?
partialResult : partialResult + [date]
}
let result = dates.count
但是是否可以对
RealmSwift
方法执行相同的操作,因为我只需要计算 SomeRealmObject
而不需要获取其内部数据?例如,有 distinct(by:)
,但它按字段的值进行比较,并且不允许指定其他条件,例如 startOfDay()
有几个问题需要克服 - 首先是 Realm 函数不允许我们“挖掘”日期 - 日期是整个日期,包括时间。
因此,使用 Realm 语法无法忽略时间。例如你不能这样做
let distinctObjects = realm.objects(SomeObject.self).distinct {by: "someDate.yyyymmdd"}
无赖。
另一个非工作的想法是使用谓词(Realm 支持一些谓词)和块来隔离日期组件
let myPredicate = NSPredicate(block: { (evaluatedDate, _) -> Bool in
//isoloate the yyyy mm dd components for evaluation
})
可惜,Realm“仅支持复合、比较和常量谓词”
(许多)解决方案之一是考虑存储的内容 - Date() 对象实际上是一个非常具体的时间戳,其中包括时间。但这不是您的
distinct
所需要的 - 它需要年、月和日
因此,将要比较的日期组件存储为单独的属性;可能是字符串或没有时间成分的日期
class SomeRealmObject: Object {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var date: Date
@Persisted var dateString = "" //stored as yyyymmdd
//or
@Persisted var dateNoTime: Date //stored as a date with 0's as time
}
可以通过提取要区分的日期组件来构建
dateNoTime
属性,创建一个新的日期对象并存储它;例如
let components = DateComponents(year: 2023, month: 04, day: 01)
let theDate = Calendar.current.date(from: components)
从那里有很多路径,一种是使用 Realm 属性支持的函数或计算属性来处理日期,因此在对象上设置日期时,它会写出实际的时间戳版本以及使用的时间戳版本为了独特。
class SomeRealmObject: Object {
@Persisted(primaryKey: true) var _id: ObjectId
@Persisted var date: Date
@Persisted var dateString = "" //stored as yyyymmdd
func writeDate(withDate: Date) {
self.date = withDate
self.dateString = //break down withDate to yyyymmdd
}
}
然后你可以使用 Realms
distinct
来获取结果
let distictObjects = realm.objects(SomeObject.self).distict(by: ["dateString"]
*注意,这也可以通过将对象加载到数组中并然后使用 Swift 谓词进行评估来完成,但这可能会导致内存问题并且可能会更慢。