swift - 由于 Realm [iOS] 中缺少 GroupBy 和 Sum,操作非常缓慢

标签 swift realm

我正在尝试构建一个会计应用程序,其中可以有很多帐户,每个帐户可以有很多条目。每个条目都有日期和金额。

条目链接到 Account 类,如下所示:

let entries = LinkingObjects(fromType: Entry.self, property: "account").sorted(byKeyPath: #keyPath(Entry.date))

我想按帐户名称分组,得到任何给定日期之间每个月的金额总和。出于报告目的,日期可能会有所不同。

Realm 没有 groupby 函数,我无法轻松获得列为帐户名称、总计、平均值、sumOf(month1)、sumOf(month2) 等的结果

因此;我需要用代码来做,但结果很慢。我的代码中是否缺少任何可以显着提高计算速度的特定 Realm ?

此代码正在为每个帐户和每个时期运行(对于年度报告,这意味着每个帐户运行 12 次)以及运行缓慢的原因:

    let total: Double = realm
        .objects(Entry.self)
        .filter("_account.fullPath == %@", account.fullPath)
        .filter("date >= %@ AND date <= %@", period.startDate, period.endDate)
        .filter("isConsolidation != TRUE")
        .sum(ofProperty: "scaledAmount")

下面是完整的代码,我必须循环每个帐户并为每个期间运行查询:

private func getMonthlyValues(for accounts: [Account], in realm: Realm, maxLevel: Int) -> String {
    guard accounts.count > 0 else { return "" }
    guard accounts[0].displayLevel < maxLevel else { return "" }

    var rows: String = ""
    for account in accounts.sorted(by: { $0.fullPath < $1.fullPath }) {
        if account.isFolder {
            let row = [account.localizedName.htmlColumn].htmlRow
            rows += row
            rows += monthlyValues(for: Array(account.children), in: realm, maxLevel: maxLevel)
        } else {
            var row: [String] = []
            var totals: [Double] = []

            // period has a start date and an end date
            // monthlyPeriods returns the period in months
            // for a datePeriod starting February 10, and ending in November 20 (for whatever reason)
            // monthlyPeriods returns 10 periods for each month starting from [February 10 - February 28],
            // and ending [November 1 - November 20]
            // below gets the some for the given period for the current account
            // for this example it runs 10 times for each account getting the sum for each period
            for period in datePeriod.monthlyPeriods {
                let total: Double = realm
                    .objects(Entry.self)
                    .filter("_account.fullPath == %@", account.fullPath)
                    .filter("date >= %@ AND date <= %@", period.startDate, period.endDate)
                    .filter("isConsolidation != TRUE")
                    .sum(ofProperty: "scaledAmount")

                totals.append(total)
            }

            let total = totals.reduce(0, +)
            guard total > 0 else { continue }
            let average = AccountingDouble(total / Double(totals.count)).value
            row.append("\(account.localizedName.htmlColumn)")
            row.append("\(total.htmlFormatted().htmlColumn)")
            row.append("\(average.htmlFormatted().htmlColumn)")
            row.append(contentsOf: totals.map { $0.htmlFormatted().htmlColumn })
            rows += row.htmlRow
        }
    }
    return rows
}

非常感谢任何帮助。

最佳答案

由于您没有使用 Results 的自动更新属性,我尝试的不是每个月运行不同的查询,而是使用单个查询获取所有条目,然后使用 Swift 的内置 进行过滤和求和filterreduce 函数,这样你可以减少 Realm 查询的开销。

只需让 let entries = realm.objects(Entry.self) 使用单个查询存储所有条目,然后您可以使用 Array(entries).filter({$0 .account.fullPath == account.fullPath}) 等。对于每个帐户和日期,这不会在您每次进行计算时查询 Realm。如果您的条目不会在计算之间发生变化,您甚至可以使用 let entries = Array(realm.objects(Entry.self))

立即将条目转换为数组

关于swift - 由于 Realm [iOS] 中缺少 GroupBy 和 Sum,操作非常缓慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45939684/

相关文章:

xcode - 通过 Swift 访问 MacOS 中的键盘设置

ios - 如何在不使用单例的情况下在多个 View Controller 之间传递数据?

swift - 提交到 App Store 时出现 Realm 错误

PHP 读取realm.io 文件

android - 当我插入数据库时​​,Realm 抛出 NullPointerException

ios - 属性字符串仅更改字体大小,不更改字体名称

ios - 在导航 Controller 中处理 UIBarButtonItems 的色调颜色变化

ios - 迁移后 Realm 不工作

ios - 在 Realm 中更新表

swift - 如何在我的 Package.swift 文件中添加对 RealmSwift 的依赖?