You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 19:05:43