swiftcore-datansfetchrequest

CoreData Fetching and Filtering


I have a question concerning CoreData.

Let's say I have 2 CoreData entities SchoolClass and Child in the CoreData-database which has multiple school classes in it, each class with multiple children.

extension SchoolClass {
    …
    @NSManaged  public var children: NSSet?
    …
}

extension Child {
    …
    @NSManaged  public var schoolClass: SchoolClass?
    @NSManaged  public var age: Int?
    …
}

From one point of my app, I have to fetch all children of a specific class that match certain additional criterias.

I see two ways to do that:

  1. handle the filtering in the SchoolClass object. For example, via a computed property and return the array from there:
extension SchoolClass {
    …
    var filteredChildren: [Child] {
        let set = children as? Set<Child> ?? []
        let filteredSet = set.filter{ $0.age < 10}
        return filteredSet
    }
    …
}
  1. with a FetchRequest:
let fetchRequest: NSFetchRequest<Child> = Child.fetchRequest()
let predicate1 =  NSPredicate(format: "schoolClass === %@", targetSchoolclass)
let predicate2 = NSPredicate(format: "age < 10")
let predicate = NSCompoundPredicate(type: .and, subpredicate: [predicate1, predicate2])
fetchRequest.predicate = predicate
if let fetchedChildren = try? context.fetch(fetchRequest) {
    …
}

Which one is more advisable? The first one seems more logical to me since it only has to check the children in the specific school class I'm interested in. On the other hand, I don‘t really understand what magic is happening behind the scenes of a CoreData fetchRequest.


Solution

  • The first one is faster. The querying the relationship is faster as it is already indexed, and may already be in memory. Even if you have a VERY large set of possible children and only want a few in the set, the relationship is still much faster. I personally had a had a similar situation with querying all the messages sent by a user in chat app. Even though most messages were not in the particular chat I was interested it, queuing the relationship - a not a new fetch - was orders of magnitude faster.

    You can easily prove this for yourself by loading up a thousand fake entities and then time the difference between faulting a filtering a relationship verse a fetch.