Ika
Ika

Reputation: 1773

I want to sort the List of RealmSwift

I am using RealmSwift. Data is a one-to-many relationship.

I'm having trouble because I don't know how to sort the list in RealmSwift.

I want to sort the tasks linked to the TaskList.

Thank you.

class TaskList: Object, Identifiable {
    @objc dynamic var id = NSUUID().uuidString
    @objc dynamic var title = ""
    @objc dynamic var createdAt = NSDate()

    var tasks: List<Task> = List<Task>()

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

class Task: Object, Identifiable {
    @objc dynamic var id = NSUUID().uuidString
    @objc dynamic var title = ""
    @objc dynamic var createdAt = NSDate()

    private let lists = LinkingObjects(fromType: TaskList.self, property: "tasks")
    var list: TaskList { return list.first! }

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

Upvotes: 0

Views: 96

Answers (3)

Jay
Jay

Reputation: 35657

I think this is a one line answer. If you know which TaskList object you want to get the tasks for, and you want them ordered by say, creation date. This will do it

let taskResults = realm.objects(Task.self)
                       .filter("ANY lists == %@", taskList)
                       .sorted(byKeyPath: "createdAt")

Upvotes: 0

Rob C
Rob C

Reputation: 5073

If you want your tasks stored in an ordered fashion you'll have to manually do an ordered insert.

extension List {
    func insert<V: Comparable>(_ object: Element, orderedBy keyPath: KeyPath<Element, V>) {
        var index = 0
        for i in 0..<count {
            if self[i][keyPath: keyPath] >= object[keyPath: keyPath] {
                break
            }
            index = i + 1
        }
        insert(object, at: index)
    }
}

let list = TaskList()

let tasks = [
    Task(title: "J"),
    Task(title: "Z"),
    Task(title: "T"),
    Task(title: "J"),
    Task(title: "Z"),
]

tasks.forEach {
    list.tasks.insert($0, orderedBy: \.title)
}

However, I find it much easier to keep Lists unsorted and retrieve sorted Results whenever I need to display the data. To sort by a single property just call sorted(byKeyPath:):

let sortedTasks = taskList.tasks.sorted(byKeyPath: "title")

To sort by multiple fields call sorted(by:):

let sortedTasks = taskList.tasks.sorted(by: [
    SortDescriptor(keyPath: "title"),
    SortDescriptor(keyPath: "createdAt")
])

Alternatively, you can add a sorted property to your Model:

class TaskList: Object, Identifiable {
    @objc dynamic var id = UUID().uuidString
    @objc dynamic var title = ""
    @objc dynamic var createdAt = Date()

    var tasks = List<Task>()

    lazy var sortedTasks: Results<Task> = tasks.sorted(byKeyPath: "title")

    override class func ignoredProperties() -> [String] {
        return ["sortedTasks"]
    }

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

Upvotes: 1

David Pasztor
David Pasztor

Reputation: 54716

You cannot get a LinkingObjects itself to be sorted, but you can call LinkingObjects.sorted(byKeyPath:), which returns a Results instance containing all elements of the LinkingObjects, just sorted.

class Task: Object, Identifiable {
    @objc dynamic var id = NSUUID().uuidString
    @objc dynamic var title = ""
    @objc dynamic var createdAt = NSDate()

    private let lists = LinkingObjects(fromType: TaskList.self, property: "tasks")
    lazy var sortedLists = lists.sorted(byKeyPath: "createdAt")
    var list: TaskList { return list.first! }

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

Upvotes: 0

Related Questions