iosswiftnscompoundpredicate

iOS Swift Compound Predicate


I'm trying to do a search for specific items within Core Data

I have an Entity Colour, which has a NSSet of ProjectColour Entities. The ProjectColour Entities have a field called project which is a Project Entity, and two int fields called fullLeft and partialLeft. This has a field called drillType which is a string.

I'm trying to all objects that have a drillType of Square and both fullLeft and partialLeft > 0

I've tried

if searchedText.lowercased() == "square" {
    let predicateNumbers = NSPredicate(format: "ANY projectColours.fullLeft > 0 OR ANY projectColours.partialLeft > 0")
    let predicateDrillType = NSPredicate(format: "ANY projectColours.project.drillType == 'Square'")

    fetchRequest.predicate = NSCompoundPredicate(type: .and, subpredicates: [predicateNumbers, predicateDrillType])
}

This works when searching for Round as the type but with squares, its returning the wrong objects i.e. Two objects, one which is a square but partial and full are equal to 0 The second is a Round which has partial equal to 1

Example 3 Colour Objects

3 Project Colour Objects

When searching, I get for square, I get all 3 results return, even through the second Project Colour object is Round

When searching for text, I want all ProjectColour.project.drillType of Square and ProjectColour.fullLeft > 0 AND ProjectColour.partialLeft > 0

fetchRequest.predicate = NSPredicate(format: "ANY projectColours.project.drillType == 'Square'") - Works

fetchRequest.predicate = NSPredicate(format: "ANY projectColours.fullLeft > 0 OR ANY projectColours.partialLeft > 0") - Works

But when I try and combine the two it doesn't work


Solution

  • Assuming that you want to search for all Colour objects which have some related ProjectColour object with the given project.drillType and positive fullLeft and positive partialLeft: You need a SUBQUERY for such a request. Something like (untested):

    let pred = NSPredicate(format: """
        SUBQUERY(projectColours, $pc, $pc.fullLeft > 0
                                        AND $pc.partialLeft > 0
                                        AND $pc.project.drillType ==[c] %@
                ).@count > 0
    """, searchedText)
    

    Note also that keyword substitution with %@ is preferred over string literals inside the predicate format string, and that ==[c] can be used for case-insensitive string comparison (so that the search text does not need to be converted to lowercase)