I have two Core Data entities: Parent
and Child
.
Parent
has a property children
for the set of children
Each Child
has a parent
property linking it to its parent, and an age
property.
(My data is more complex than this, but that's not relevant to the question)
I have a NSPredicate
for the Parent
entity that selects a set of parents and a NSPredicate
for the Child
entity that selects entities based on age
What I want to do is construct a single NSPredicate
for a FetchRequest<Child>
that returns the set of Child
entities that meets both of the individual predicates
I know I can retrieve an array of Parent
entities that meet their predicate ('parents
') then have a child predicate something like NSPredicate(format: "parent IN %@", parents)
and include that in a compound AND with the child predicate, but there could be hundreds of parents meeting their predicate and it looks to me a but of a kludge to have two separate queries.
The FetchRequest
needs to be FetchRequest<Child>
as it's used in a SwiftUI view, so I can't just build an array of the results.
I suspect that I can do this with a SUBQUERY predicate but I can't work out how to embed the parent predicate into the SUBQUERY. I get errors like Problem with subpredicate TRUEPREDICATE
in the predicate string for the Parent
entity.
Hopefully that makes sense? Any ideas or suggestions?
Thanks
If the relationship from Child
to Parent
is to-one, then there is no need for SUBQUERY. In the format string for the parent predicate (which you can obtain with predicateFormat
), you can replace each parent attribute name in the the string with the keypath to that attribute from the child, ie
attribute
becomesparent.attribute
The resulting predicate can then be combined with the child predicate using NSCompoundPredicate
's andPredicateWithSubpredicates
.
If parsing the predicateFormat is impractical, another option is to use NSFetchRequestExpression
to pass the results of one fetch as an argument to another (it gets converted to an SQL subselect). Something like this:
let parentFetch = Parent.fetchRequest()
parentFetch.predicate = parentPredicate // your existing predicate to fetch the parent objects
parentFetch.resultType = .managedObjectIDResultType
let ctxtExp = NSExpression(forConstantValue: managedObjectContext)
let fetchExp = NSExpression(forConstantValue: parentFetch)
let fre = NSFetchRequestExpression.expression(forFetch: fetchExp, context: ctxtExp, countOnly: false)
let childFetch = Child.fetchRequest()
let subPredicate = NSPredicate(format:"parent IN %@",fre)
let combinedPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [subPredicate, childPredicate]) // childPredicate is you existing predicate to fetch the correct Child objects
childFetch.predicate = combinedPredicate
... proceed to execute the fetch against the relevant context