Using NSCompoundPredicate with a list of lists

119 Views Asked by At

I have a large list of recipes and inside of each recipe is a list of ingredients. I want to write a query that will return a list of recipes that have both "egg" and "butter". Here is a quick screenshot of the first few recipes in my CKRecord Type. In my example code below, it returns no results though also has no errors.

Ideally, it would be great to include partial searches, for instance "egg" would still return a recipe that has "eggs" as an ingredient. It would be even better if the result would prioritize recipes that had ingredients which contains both "egg" and "butter", and then on the lesser priority of the recipe list would have recipes which had either "egg" or "butter", making the .and,subpredicates query of a higher priority than the .or,subpredicates query.

The other StackOverflow posts concerning NSCompoundPredicate that I have found do not help here when working with a list of lists that are being queried (as in my example where I have a list [ingredients] inside a list of recipes).

@objc func refresh(_ completion: @escaping (Error?) -> Void) {
    let subdeptPredicate1 = NSPredicate(format: "ANY ingredients == %@", "egg")
    let subdeptPredicate2 = NSPredicate(format: "ANY ingredients == %@", "butter")
    let predicate = NSCompoundPredicate(type: .and,subpredicates: [subdeptPredicate1, subdeptPredicate2])
        
    let sort = NSSortDescriptor(key: "recipe_id", ascending: false)
    let query = CKQuery(recordType: "Recipe", predicate: predicate)
    query.sortDescriptors = [sort]
    AttachToMainThread(forQuery: query, completion)
  }

I am able to successfully return recipes that have either "butter" or "egg" in the ingredients with this line of code, but I'm looking to prioritize recipes which include both "egg" and "butter".

    let searchText: [String] = ["butter","egg"]
    let predicate = NSPredicate (format: "ANY ingredients IN %@",argumentArray: [searchText])

I appreciate your help!

UPDATE

I found that if I just have one of these subpredicates that every recipe that returns, only has "eggs" as the first ingredient.

let subdeptPredicate1 = NSPredicate(format: "ANY ingredients == %@", "egg")
let predicate = NSCompoundPredicate(type: .and,subpredicates: [subdeptPredicate1])

I'm sure that's why I'm returning zero results when I use both "eggs" and "butter" because they will never both be in the first ingredient.

1

There are 1 best solutions below

0
On

It was an error on my end. I found that the way I was parsing the csv file cause the problem. Notice the first ingredient is the only without a space in the beginning of the word.

This does precisely what I'm wanting:

    let searchTextA: [String] = ["egg"," egg"]
    let subPred1 = NSPredicate (format: "ANY ingredients IN %@",argumentArray: [searchTextA])
    
    let searchTextB: [String] = ["butter"," butter"]
    let subPred2 = NSPredicate (format: "ANY ingredients IN %@",argumentArray: [searchTextB])
    
    let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [subPred1, subPred2])