Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to build a complex NSCompoundPredicate?

I need to build an NSPredicate with many pieces of data. For example in SQL I would do something like the following:

SELECT * 
  FROM TRANSACTIONS
  WHERE CATEGORY IN (categoryList)
    AND LOCATION IN (locationList)
    AND TYPE IN (typeList)
    AND NOTE contains[cd] "some text"
    AND DATE >= fromDate
    AND DATE <+ toDate

I'm struggling with how to build this as an NSPredicate for use with Core Data. I've read the documentation... which only provides simplistic examples. If anybody can point me to a more complex example I would certainly appreciate it.


Well, I had an answer out here for two years that many people found helpful. My post was deleted. Here is the updated URL with the solution.

https://www.radeeccles.com/convert-sql-statement-to-an-nspredicate-for-use-with-core-data/

like image 288
radesix Avatar asked Oct 17 '10 23:10

radesix


1 Answers

What you need to do is to create a Predicate for each one of your clauses. For example let's break down your query:

  1. SELECT * FROM TRANSACTIONS
  2. WHERE CATEGORY IN (categoryList)
  3. AND LOCATION IN (locationList)
  4. AND TYPE IN (typeList)
  5. AND NOTE contains[cd] "some text"
  6. AND DATE >= fromDate AND DATE <+ toDate

Based on this, you have 5 predicates (2-6). So let's work on them one by one.

 NSPredicate *inCategoryPredicate = [NSPredicate predicateWithFormat:@"Category IN %@", categoryList];

 NSPredicate *locationPredicate = [NSPredicate predicateWithFormat:@"Location IN %@", locationList];

 NSPredicate *typePredicate = [NSPredicate predicateWithFormat:@"Type IN %@", typeList];

 NSPredicate *notePredicate = [NSPredicate predicateWithFormat:@"Note contains[c] %@", @"Some Text"];

 NSPredicate *startDatePredicate = [NSPredicate predicateWithFormat:@"Date => @", fromDate];

 NSPredicate *endDatePredicate = [NSPredicate predicateWithFormat:@"Date <= @", toDate];

Now you just need to join them into just one predicate: Apple's documentation states:

You should structure compound predicates to minimize the amount of work done. Regular expression matching in particular is an expensive operation. In a compound predicate, you should therefore perform simple tests before a regular expression;

This being said then you should start with the "easy" predicates first. So:

NSCompoundPredicate *compoundPredicate = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects: startDatePredicate, endDatePredicate, inCategoryPredicate, locationPredicate, typePredicate, notePredicate];

You can always get an idea of what the predicate (sql where) looks like if you NSLog it.

like image 165
Ares Avatar answered Nov 13 '22 11:11

Ares