Skip to content

Query Enhancements

snej edited this page Oct 16, 2014 · 6 revisions

Version 1.0.3 adds some new functionality to view queries:

  • Sorting by criteria other than the key order (using NSSortDescriptor)
  • Filtering the result set (using NSPredicate)
  • String or array prefix matching, to find things like "keys starting with 'foo'" or "array keys whose first item is 2014".
  • inclusiveEnd and inclusiveStart properties (which default to YES but can be set to NO.)

None of these fundamentally alter the map/reduce indexing, and they're all things you could already do yourself, if awkwardly; but they make querying smoother and more intuitive, and they pave the way for future higher level interfaces like Core Data-style fetch requests or Couchbase's N1QL query language.

Sorting

The new property CBLQuery.sortDescriptors can be set to an NSArray of NSSortDescriptor objects, overriding the default by-key ordering.

A sort descriptor primarily contains a key-path string that specifies an Objective-C property to sort by. As used here, the sort descriptors are being used to sort CBLQueryRow objects, so the key-paths are interpreted relative to those objects. They should start with "value" to refer to the value, or "key" to refer to the key. A limited form of array indexing is supported, so you can refer to key[1] or value[0] if the key or value are arrays. (This only works with indexes from 0 to 3.)

For example, the key-path value.year would sort NSDictionary-based values by their year property, and the key-path value[0] would sort array-based values by their first element. If the value is a scalar like a number or string, you can just use value by itself to sort by it.

REST API: This feature is not available since it depends on Cocoa classes.

Filtering

The new property CBLQuery.postFilter can be set to an NSPredicate that filters the resulting query rows. The predicate is called on every row returned from the query, and if it returns NO, the row is skipped instead of being added to the CBLQueryEnumerator.

Since the predicate is called on the CBLQueryRow instance, it can operate only on properties of that object. Just as described in the previous section, key-paths are interpreted relative to the CBLQueryRow, so they should start with value to refer to the value, or key to refer to the key.

Since this filtering happens during querying (and after a query row has been expanded into an object tree) it's inherently much slower than B-tree based index lookups. Don't use it in place of intelligent map-reduce index and query design, or you'll get slow performance!

REST API: This feature is not available since it depends on Cocoa classes.

Prefix Matching

It's always been possible to constrain a query to match a string or array prefix, but it's been awkward and unintuitive. The new CBLQuery.prefixMatchLevel property makes it a lot easier. It defaults to 0; for basic prefix matching, set it to 1.

If your keys are strings, to match a prefix you'd set up the query like this:

// Find all keys that start with "f":
query.startKey = query.endKey = @"f";
query.prefixMatchLevel = 1;

Or if your keys are arrays, you can match all keys with the given first item:

// Find all keys whose first item is 2014:
query.startKey = query.endKey = @[@2014];
query.prefixMatchLevel = 1;

The cases where you'd need to set prefixMatchLevel to a value greater than 1 are those where you're matching a prefix inside an array. For example:

// Find all keys in 2014 whose product name starts with "f":
query.startKey = query.endKey = [@2014, @"f"];
query.prefixMatchLevel = 2;  // prefix match on "f...", not [2014, ...]

REST API: This feature is available as the URL query-string property prefix_match_level.

Non-Inclusive Start/End

This one's easy. Setting the property inclusiveEnd to NO prevents a row whose key is equal to endKey from appearing in the result. Same thing for inclusiveStart and startKey.

(Those who know CouchDB will recognize inclusiveEnd, and this property has actually always existed inside Couchbase Lite but was accidentally left out of the public API in 1.0. The inclusiveStart property is new, though; for some reason CouchDB never added it.)

REST API: These are available as the URL query-string properties inclusive_start and inclusive_end.