Need another set of eyes on this one.
The issue is we are intermittently getting incorrect averages using the Swift .average function on a List. We believe the results returned from a filter are what’s causing the .average function to be incorrect based on the number of returned results from the filter
There are three objects in the items List, and then what Realm says is the average of the ‘value’ property. The properties are transaction_id, transaction_name, account, and value. There’s a simple loop in the ItemClass that prints it’s transactions when the GetAverageValue function is called which also prints the average calculated by Realm.
As you can see, the three values are 10, 20 and 30 and the average is 20, but realm is showing 15.0
AC8AABC6-C053-41B1-AD13-0C031B7766F2 Transaction 0 Account 0 10.0
69E9CC4A-2A3A-4437-9A7A-C6EEAA5899BD Transaction 1 Account 0 20.0
D13E6164-E346-4A39-A561-6A780185025B Transaction 2 Account 0 30.0
Average: 15.0
There are three Realm objects, AccountClass, TransactionClass and ItemClass. There’s one account with an id of 1 and one item with a name Item 0.
class AccountClass: Object {
@objc dynamic var account_id = 0
@objc dynamic var account_name = ""
let transactionList = List<TransactionClass>()
override static func primaryKey() -> String {
return "account_id"
}
}
class TransactionClass: Object {
@objc dynamic var transaction_id = UUID().uuidString
@objc dynamic var transaction_name = ""
@objc dynamic var account: AccountClass!
@objc dynamic var _amount = 0.0
override static func primaryKey() -> String {
return "transaction_id"
}
}
class ItemClass: Object {
@objc dynamic var item_id = UUID().uuidString
@objc dynamic var item_name = ""
let transactions = List<TransactionClass>()
func getAverageValue() -> Double {
self.transactions.forEach { trans in
let id = trans.transaction_id
let acct = trans.account.account_name
let name = trans.transaction_name
let amt = trans.amount
print(id, name, acct, amt)
}
let avgValue: Double = self.transactions.filter("account.account_id == 1").average(ofProperty: "_amount") ?? 0.0
return avgValue
}
override static func primaryKey() -> String {
return "item_id"
}
}
and then a simple function that creates three transactions and adds them to the existing item
func avgTest() {
let realm = try! Realm
let i0 = realm.objects(ItemClass.self).filter("item_name == 'Item 0'").first!
let account = realm.object(ofType: AccountClass.self, forPrimaryKey: 1)
let t0 = TransactionClass()
t0.transaction_name = "Transaction 0"
t0.account = account
t0.amount = 10.0
let t1 = TransactionClass()
t1.transaction_name = "Transaction 1"
t1.account = account
t1.amount = 20.0
let t2 = TransactionClass()
t2.transaction_name = "Transaction 2"
t2.account = account
t2.amount = 30.0
let a = [t0, t1, t2]
try! realm.write {
i0.transactions.append(objectsIn: a)
}
let avg = i0.getAverageValue()
print(avg)
}
note that even if this let avg = i0.getAverageValue()
is called outside that function, the results is the same; 15.0
A bit more info.
Note that within the getAverageValue function, it filters where “account.account_id == 1” and it appears that filter is failing on an intermittent basis which is causing the average function to not calculate correctly.
I changed the code to print out the filtered results, and then print the average. Sometimes finds two results, sometimes 3 and sometimes just 1. I ran the test several times, deleting ALL the Realm files and creating the data fresh each time and then in a separate button in the UI, called the getAverageValue function
Run 1
A1E1DC70-7CFB-46CA-8D93-71EE9B3600A1 Transaction 0 10.0
D91F2AFE-3BEC-4B2E-BE5E-212AED0794F2 Transaction 2 30.0
20.0
Run 2
AE8E587B-F137-4351-BF7F-27F130073E18 Transaction 0 10.0
9D7A1C56-E47F-41E5-8881-A8CA7273AF25 Transaction 1 20.0
15.0
Run 3
242A7F57-5546-45F5-9905-D5A759BB2F5A Transaction 0 10.0
10.0