Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS Compound Predicates

I am writing an application that has a database of photos. Each photo has several tags associated with it and the application has a search page with a lot of toggles that allows users to search for photos based on only the tags that are of interest to them. Each of these tags have stored integer ID's because they correspond to an external database's IDs, so I am trying to look them up simply by ID. All of the ID fields are indexed.

The problem arrises when the predicates that I am writing become quite large because the user can select from lots of different tags to filter on. Those tags are grouped into 3 categories [publications, brands & products], and so my queries are setup to be 'OR'ed within a category, and 'AND'ed across these categories.

An example query predicate ends up looking something like this:

(parentPublication.publicationId==1 OR parentPublication.publicationId==2 OR parentPublication.publicationId==5) 
AND (ANY brands.brandId==12 OR ANY brands.brandId==2 OR ANY brands.brandId==0 OR ANY brands.brandId==3 OR ANY brands.brandId==5 OR ANY brands.brandId==6 OR ANY brands.brandId==7) 
AND (ANY products.productId==2 OR ANY products.productId==3 OR ANY products.productId==6)

They can get much larger, but you get the point. My issue is, since all of these are performing expensive joins, once the user selects more than 10 or 15, the queries run extremely long, and can even cause the app to crash.

It seems like it would be more efficient to write something like:

parentPublication.publicationId IN (1,2,5) 
AND (ANY brands.brandId IN (12,2,0,3,5,6,7))
AND (ANY products.productId IN (2,3,6))

But I cannot seem to get that syntax to work.

So my question is: is this type of syntax supported, and if so, can someone show me how to properly write it?

Or is there a better way to approach this type of queries against Core Data all together?

like image 642
k.v Avatar asked Aug 09 '13 23:08

k.v


1 Answers

Use collection predicates, like

[NSPredicate predicateWithFormat:@"parentPublication.publicationID in %@", pubIDs];
[NSPredicate predicateWithFormat:@"brands.brandID in %@", brandIDs];
[NSPredicate predicateWithFormat:@"product.productID in %@", productIDs];

Now you simply have to keep three arrays of attributes and make a three-way compound predicate with andPredicateWithSubpredicates.

[NSCompoundPredicate andPredicateWithSubPredicates:@[
   pubPredicate, brandPredicate, productPredicate]];

Should perform OK.

like image 125
Mundi Avatar answered Nov 22 '22 00:11

Mundi