3

I am learning SwiftData and would like to use it to convert my current app to use SwiftData. I am trying to construct a SwiftDate Query to sort an array of Items by date. The Items array is a property within the main model. All examples I have seen have a Query that uses the first level attribute to sort on (@Query(sort: \TaskItem.name) var tasks: [TaskItem]) but I am looking at a Query to sort on the second level (TaskItems.items.date). I am looking for help/direction. See my models below

@Model
final class TaskItems {
    @Attribute(.unique) var name: String
    @Relationship(deleteRule: .cascade)
    var items: [Item]?
    
    init(name: String, items: [Item]? = nil) {
        self.name = name
        self.items = items
    }
}

@Model
final class Item {
    @Attribute(.unique) let id = UUID().uuidString
    var tag: String
    var date: Date
    
    init(tag: String, date: Date) {
        self.tag = tag
        self.date = date
    }
}

In my View, I have the main Query as

@Query var taskItems: [TaskItems]

and I am trying to display the Items which is a property of TaskItems sorted by the date.

Here is what I tried which I know is not right and does not compile.

@Query(FetchDescriptor<Item>(sortBy: [SortDescriptor(\TaskItems.items.date, order: .forward)])) var items: [Item]

Appreciate any direction/help

4
  • @Query(FetchDescriptor<Item>(sortBy: [SortDescriptor(\Item.date, order: .forward)])) var items: [Item] would be the correct way but you need a predicate as well to filter on TaskItems. In what context do you want to use the sorted Item array, is it in a different view from the taskItems or the same view? Commented Mar 15, 2024 at 18:14
  • I am using it in a different View called the ItemView where I am passing the specific TaskItem. For example, I am passing in taskItem[1] Commented Mar 15, 2024 at 18:30
  • Then use taskItem.items.sorted(using: ...) or taskItem.items.sorted(by: ...) in the ItemView, no need for a query. Commented Mar 15, 2024 at 19:13
  • I was doing what you suggested but the challenge is if I have large amount of data, it is slow. So, was wondering if I could construct a query to get the items sorted by date Commented Mar 15, 2024 at 19:22

1 Answer 1

3

To solve this with a @Query you first need to update your models by fully defining the relationship between them.

  • Add a reference to TaskItems in Item, the property needs to be optional since the other end is optional for the predicate to work
var task: TaskItems?
  • Update the Relationship in TaskItems by defining what the inverse property is
@Relationship(deleteRule: .cascade, inverse: \Item.task) 
var items: [Item]?
  • Add the query to the sub-view
@Query(filter: Predicate<Item>.false) private var items: [Item]

init(task: TaskItems) {
    let id = task.persistentModelID
    let fetchDescriptor = FetchDescriptor<Item>(predicate: #Predicate { $0.task?.persistentModelID == id},
                                                sortBy: [SortDescriptor(\.date, order: .forward)])
    _items = Query(fetchDescriptor)
 }
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.