Search code examples
swiftrealm

Realm sort by property sum which is in another table


I am trying to re-order my cells in tableView by the highest age, but the problem is that I have two tables. I am using Realm's database to store data, so my data comes from there and also I am somehow limited. In SQL I would join tables to achieve what I want but I know that Realm is an object-based database, so the concept of joins in queries doesn't apply to it.

Let's say I have Class Parent and Child

@objcMembers class Parent: Object{
    dynamic var name: String = ""
    let children = List<Child>()

    convenience init(name: String) {
        self.init()
        self.name = name
    }

    override static func primaryKey() -> String?{
        return "name"
    }
}

@objcMembers class Child: Object{
        dynamic var name: String = ""
        dynamic var age: Int = 0
        dynamic var parent: Parent? = nil

        convenience init(name: String, age: Int) {
            self.init()
            self.name = name
            self.age = age
        }

        override static func primaryKey() -> String?{
            return "name"
        }
    }

And then I have two variables:

  1. var parentsArray: Results<Parent>!
  2. var childrenArray: Results<Child>!

And like this I assign values from database:

parentsArray = realm.objects(Parent.self)
childrenArray = realm.objects(Child.self)

Now lets say I have John and Peter. Peter has 2 kids(Tim(age = 1) and Tom(age = 3)). John has one kid Thomas(age = 2). So the Parents order should be Peter and John

I have tried everything but can't find answer.

So my question is, how should you order by the given criteria?


Solution

  • You can sort the array of parents using custom sort function:

    let sorted = parentsArray.sorted {
      ($0.children.sum(ofProperty: "age") as Int) > ($1.children.sum(ofProperty: "age") as Int)
    }
    

    Accordingly, if you'll need to sort by the maximum age of children, you'll just use another function:

    $0.children.max(ofProperty: "age") as Int
    

    As a side note, dynamic var parent: Parent? = nil implies that you're settings parent manually. Instead, you should use LinkingObjects – a list of objects that are linking to the current one:

    let parents = LinkingObjects(fromType: Parent.self, property: "children")
    

    This may seem inconvenient as it introduces many-to-many relationship instead of one-to-many, but this way Realm will take care of providing inverse relationship.