Realm嵌套对象过滤:如何通过查询保留type为audio的内层Model
Realm嵌套对象过滤问题
模型定义
我有以下三个Realm模型:
YearDatabaseModel
class YearDatabaseModel: Object { @Persisted var year: Int @Persisted var months = List<MonthsDatabaseModel>() override static func primaryKey() -> String? { return "year" } }
MonthsDatabaseModel
final class MonthsDatabaseModel: Object { @Persisted var id: String @Persisted var media = List<Model>() override static func primaryKey() -> String? { return "id" } }
Model
public class Model: Object { @Persisted public var id: String @Persisted public var type: String }
需求说明
需要返回所有YearDatabaseModel实例,同时过滤嵌套MonthsDatabaseModel中的Model,仅保留type等于"audio"的条目。
之前尝试使用SUBQUERY语句,但它仅过滤出包含audio类型媒体的Year,并未过滤每个Year下Months中的Model列表:
let predicate = NSPredicate( format: "SUBQUERY(months.media, $media, $media.type = %@).@count > 0", "audio")
我希望直接借助Realm的查询能力实现嵌套对象过滤,而非先获取全量结果再通过flatMap处理。
模型关系:YearDatabaseModel包含多个MonthsDatabaseModel,每个MonthsDatabaseModel包含多个Model。
解决方案
核心限制说明
Realm的Object子类是与数据库实时绑定的,其关联集合(如List)会完整反映数据库中的数据,无法通过单次查询直接修改返回对象的嵌套集合内容。但可以通过以下方式实现需求:
方案1:分步查询过滤嵌套媒体
先筛选出包含audio媒体的Year,再对每个Year下的Months单独过滤媒体:
// 第一步:获取所有包含audio类型媒体的Year let yearsWithAudio = realm.objects(YearDatabaseModel.self).filter( "SUBQUERY(months.media, $media, $media.type = %@).@count > 0", "audio" ) // 第二步:遍历每个Year,过滤对应Month下的audio媒体 for year in yearsWithAudio { for month in year.months { let audioOnlyMedia = month.media.filter("type = %@", "audio") // 使用audioOnlyMedia,即该Month下仅有的audio类型Model } }
方案2:投影到自定义结构体
如果需要将过滤后的数据封装成独立的结构,可以定义投影模型,通过Realm查询后构造:
// 定义投影结构体 struct YearProjection { let year: Int let months: [MonthProjection] } struct MonthProjection { let id: String let audioMedia: [Model] } // 查询并构造投影数据 let yearsWithAudio = realm.objects(YearDatabaseModel.self).filter( "SUBQUERY(months.media, $media, $media.type = %@).@count > 0", "audio" ) let filteredYears = yearsWithAudio.map { year in let filteredMonths = year.months.map { month in let audioMedia = month.media.filter("type = %@", "audio").compactMap { $0 } return MonthProjection(id: month.id, audioMedia: audioMedia) } return YearProjection(year: year.year, months: filteredMonths) }
方案3:通过反向关联查询
给模型添加反向关联后,可以直接从audio类型的Model向上关联到对应的Month和Year:
// 先给Model添加反向关联到MonthsDatabaseModel extension Model { @Persisted(originProperty: "media") var parentMonth: LinkingObjects<MonthsDatabaseModel> } // 给MonthsDatabaseModel添加反向关联到YearDatabaseModel extension MonthsDatabaseModel { @Persisted(originProperty: "months") var parentYear: LinkingObjects<YearDatabaseModel> } // 查询所有audio类型的Model,再关联到对应的Year let audioMedia = realm.objects(Model.self).filter("type = %@", "audio") let uniqueYears = audioMedia .compactMap { $0.parentMonth.first?.parentYear.first } .reduce(into: Set<YearDatabaseModel>()) { $0.insert($1) } .map { $0 }
内容的提问来源于stack exchange,提问作者Amir Ardalan
相关产品推荐
相关产品推荐

