0
votes

Given a core data entity setup like this

  • Entity A
    • aB -> B (many to 1)
    • aC -> C (many to 1)
    • children -> Child (many to many)
  • Entity B
    • children -> Child (many to many)
  • Entity C
    • children -> Child (many to many)
  • Entity Child

I'm trying to do a query to find all Entity A's such that a set of Child entities TestChildren is found across all the reachable Children. Something like this example for a matching A entity, A1

  • TestChildren Set

    • Child1
    • Child2
    • Child3
    • Child4
  • A1 Entity

    • aB -> B1
    • aC -> C1
    • children
      • -> child1
      • -> child3
  • B1 Entity
    • children
      • -> child2
  • C1 Entity
    • children
      • -> child4

So all 4 children have been found across the various children relationships in each class.

It seems that to test for these sets I have to perform subqueries over each Children relationship, but I don't think I can express what I want with the NSPredicate format.. perhaps its just not doable at all with NSPredicates?

An idea I had was to do something like this

  predicateString += "((SUBQUERY(aB.children, $child, $child in %@).@count + SUBQUERY(aC.children, $child, $child in %@).@count + SUBQUERY(children, $child, $child in $@).@count) == $@)"
  predicateVars.append(contentsOf: [testChildren, testChildren, testChildren, testChildren.count])

Where the total of matching counts across all the children relationships have to match.. unfortunately if the same child could be present in more than one A,B, or C then this wouldn't be correct as the same child matched in two different classes would allow the total to incorrectly match.

Regardless it seems that adding up counts is not something that is even possible in NSPredicates?

The only way to really do this properly is to be able to generate a total set of all children across the 3 classes, but again there doesn't seem to be a way to express this in an NSPredicate?

Worse case I can do a simpler query and perform more logic on the returned results, but ideally I'd try to do as much heavy lifting as possible in the query.

Thanks in advance

2
If all children relationships are one-to-many then a child can't be present in more than one A, B or C. Do you want to check if all A's of the TestChildren are the same A? Or did I misunderstand the question?Willeke
You're right, I made a mistake with the description.. I've amended it now. Apologies.. its A -> B, and A->C are both many to 1 relationships and all the children are many to many, as you can see more clearly in the original question text now.jimbobuk
If anyone's interested, I've added another question working with a similar but slightly different hierarchy of entities here - stackoverflow.com/questions/51753032/…jimbobuk

2 Answers

1
votes

Predicate to find all A's with a child:

NSPredicate(format:"aB.children contains %@ OR aC.children contains %@ OR children contains %@", child, child, child)

AND predicate to find all A's with child1 and child2 and child3 and child4:

var predicateArray:[NSPredicate] = []
for child in testChildren {
    let predicate = NSPredicate(format:"aB.children contains %@ OR aC.children contains %@ OR children contains %@", child, child, child)
    predicateArray.append(predicate)
}
let finalPredicate = NSCompoundPredicate(andPredicateWithSubpredicates:predicateArray)
0
votes

An alternative version of Willeke's answer above is to build the predicates described as strings with variables as shown here

var predicateString:String = ""
var predicateVars:[Any] = []

for child in testChildren
{
  if (predicateString.count > 0)
  {
    predicateString += " && "
  }

  predicateString += "(aB.children contains %@ || aC.children contains %@ || children contains %@)"
  predicateVars.append(contentsOf: [child, child, child])
}
let predicate = NSPredicate(format: predicateString, argumentArray: predicateVars)