DEV Community

Cover image for SwiftData: Solving Filtering by an Entity in the Predicate
Kyra
Kyra

Posted on • Originally published at simplykyra.com

SwiftData: Solving Filtering by an Entity in the Predicate

I just wanted to start out by saying that this is an abridged version of my original published version from December 15, 2023 that you can find on my website here.


When moving my apps over from CoreData to SwiftData I came across a problem where I wasn't able to filter my query by another entity within its predicate. Whenever I did and tried to build the project it kept compiling and compiling and would eventually fail so the time wasted waiting while trying to solve the issue was another aggravation on top of it all.

To demonstrate the problem I took the iTour example project from Hacking with Swift and altered it a bit to showcase my problem and, eventually, the solution.

In his app there are two main data models. You have destinations you can visit and each one has a list of sights you can see at that destination. So for example if you were to visit Alberta (the destination) you could visit many sights while there like: Banff, Lake Louise, Royal Tyrrell Museum, and West Edmonton Mall. While a Destination can include multiple Sights each Sight can only belong to one Destination. His example didn't show my issue but I altered it to include a list of Sights that needed to be filtered by the id of a Destination thus recreating my problem.

Image showing one of the errors

The problem, once solved, was very simple. I was filtering the Sight data thus I could only filter by the data model Sight and no other ones. My problem came when I introduced the Destination. To get around this I took the persistentModelID from the Destination before entering into the Predicate to filter by. That worked!

Image shows the filtered data in two ways.

The working code, in case you want to use it towards your solution, is:

init(sort: [SortDescriptor<Sight>], searchString: String, destination: Destination?) {
  // Make a point of grabbing 
  if let thisID = destination?.persistentModelID {
    _sights = Query(filter: #Predicate<Sight> {
      if searchString.isEmpty {
        return $0.destination?.persistentModelID == thisID
      } else {
        return $0.destination?.persistentModelID == thisID && $0.name.localizedStandardContains(searchString)
      }
    }, sort: sort)
  } else {
    // if id is nil than I don't want ANYTHING that said you could instead return $0.name.localizedStandardContains(searchString)
    _sights = Query(filter: #Predicate<Sight> { currSight in
      return false
    }, sort: sort)
  }
}
Enter fullscreen mode Exit fullscreen mode

And with that the issue was solved! If you want more information about the problem, the example, the building issues, or the solution itself you can check out my SimplyKyra website where I published the longer and original version of this post back in December of 2023.

Hope you have a great day!

Top comments (1)

Collapse
 
dialzara profile image
Dialzara

Very useful post!