Over the weekend I experimentally added support for customizing the ordering of the rows in a CBLQueryEnumerator. You can try this out; it’s in a branch called “
” in the couchbase-lite-ios repo. (This branch is based on master, so it’s significantly ahead of 1.0.1.)
The map/reduce view always returns results ordered by key, because that’s the way the underlying index is ordered. But it can be useful to order the results of a query in some different order. This adds the ability to do that, by adding a property CBLQuery.sortDescriptors. The value must be an array of NSSortDescriptor objects, each of which specifies a key-path (relative to the CBLQueryRow), an ordering flag, and optionally a comparator. If you’ve done much Cocoa programming you’ve probably used NSSortDescriptors already; they’re used in table views and CoreData, for instance.
So: If you set a CBLQuery’s sortDescriptors property to a non-nil value, the query results will be post-processed (in memory) to sort them according to those descriptors. You can also change the sort order after the fact by calling -[CBLQueryEnumerator sortUsingDescriptors:] (with some limitations; see the header comment on that method for details.)
The key paths in the sort descriptors are relative to the CBLQueryRow objects being sorted, so usually they’ll start with “value” or “key”. For example, if your view’s values are dictionaries with a “height” property, you can use the key-path “value.height” to sort by that. Since keys and values are often arrays, but for some reason key-paths don’t handle arrays, I added a hack that lets you start a key-path with “key[n]” or “value[n]” where n is an index from 0–3.
Example:
// Find pants in sizes 30–34, sorted by length:
CBLQuery* query = [[db viewNamed: @"pants/by-size"] createQuery];
query.startKey = @30;
query.endKey = @34;
query.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey: @"value.length" ascending: YES]];
CBLQueryEnumerator* e = [query run: &error];
Some performance notes:
- The sorting happens in memory, as an extra step, so it’s slower than the default by-key sort.
- It’s possible to use document properties directly in the key-path (i.e. start it with “document.”) but I don’t recommend it since it will cause all of the documents to be dragged into memory. If a property is important enough that you need to sort by it, it should at least be emitted into the value.
- For best performance and scalability, avoid using this; instead create another view whose keys include the thing you want to sort by. But it’s not always possible to do this; sometimes you really need to specify a key range one way and then sort a different way. That’s what this feature is for.
Also, I should note that this feature is experimental and may not make it into a release in its current form. Feedback and suggestions are welcome.
—Jens