我正在尝试建立一个会计应用程序,其中可以有许多帐户,每个帐户可以有许多条目。每个条目都有日期和金额。
条目链接到Account类,如下所示:
let entries = LinkingObjects(fromType: Entry.self, property: "account").sorted(byKeyPath: #keyPath(Entry.date))
我想按帐户名进行分组,在任何给定日期之间每月的金额总和。日期可能因报告目的而有所不同。
Realm没有groupby函数我不能轻易得到一个结果,其中列是帐户名,总计,平均值,sumOf(month1),sumOf(month2)等等
因此;我需要在代码中执行此操作,但结果非常慢。我的代码中是否有任何特定的缺失会显着提高计算的速度?
此代码正在为每个帐户和每个期间运行(对于每个帐户的年度报告,这意味着每个帐户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
}
非常感谢任何帮助。
答案 0 :(得分:1)
由于您没有使用Results的自动更新属性,我会尝试不是每个月运行不同的查询,而是使用单个查询获取所有条目,然后使用Swift构建过滤和求和在filter
和reduce
函数中,这样可以减少Realm查询的开销。
只需let entries = realm.objects(Entry.self)
使用单个查询存储所有条目,然后您可以使用Array(entries).filter({$0.account.fullPath == account.fullPath})
等对每个帐户和日期进行过滤,并且每次您都不会查询Realm做计算。如果您的条目在计算之间不会发生变化,您甚至可以使用let entries = Array(realm.objects(Entry.self))
立即将条目投射到数组