1

I'm brand new to CouchDB (and NoSQL in general), and am creating a simple Node.js + express + nano app to get a feel for it. It's a simple collection of books with two fields, 'title' and 'author'.

Example document:

{
   "_id": "1223e03eade70ae11c9a3a20790001a9",
   "_rev": "2-2e54b7aa874059a9180ac357c2c78e99",
   "title": "The Art of War",
   "author": "Sun Tzu"
}

Reduce function:

function(doc) {
  if (doc.title && doc.author) {
    emit(doc.title, doc.author);
  }
}

Since CouchDB sorts by key and supports a 'descending=true' query param, it was easy to implement a filter in the UI to toggle sort order on the title, which is the key in my results set. Here's the UI:

List of books with link to sort title by ascending or descending

But I'm at a complete loss on how to do this for the author field.

I've seen this question, which helped a poster sort by a numeric reduce value, and I've read a blog post that uses a list to also sort by a reduce value, but I've not seen any way to do this on a string value without a reduce.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
SchattenJager
  • 333
  • 3
  • 15

1 Answers1

2

If you want to sort by a particular property, you need to ensure that that property is the key (or, in the case of an array key, the first element in the array).

I would recommend using the sort key as the key, emitting a null value and using include_docs to fetch the full document to allow you to display multiple properties in the UI (this also keeps the deserialized value consistent so you don't need to change how you handle the return value based on sort order).

Your map functions would be as simple as the following.

For sorting by author:

function(doc) {
  if (doc.title && doc.author) {
    emit(doc.author, null);
  }
}

For sorting by title:

function(doc) {
  if (doc.title && doc.author) {
    emit(doc.title, null);
  }
}

Now you just need to change which view you call based on the selected sort order and ensure you use the include_docs=true parameter on your query.

You could also use a single view for this by emitting both at once...

emit(["by_author", doc.author], null);
emit(["by_title", doc.title], null);

... and then using the composite key for your query.

Ant P
  • 24,820
  • 5
  • 68
  • 105
  • Oh! 'include_docs' was the missing link. I didn't realize I could return the entire document when emitting just one field. Awesome! – SchattenJager Oct 27 '15 at 14:53
  • @SchattenJager You can also emit the whole document as the value, or an arbitrary value, e.g. `emit(doc.author, [doc.author, doc.title])`. However, since views are compiled at index time and stored, this is expensive in terms of disk space when you can just use `include_docs` and store null in the view. – Ant P Oct 27 '15 at 14:55
  • At first glance it felt like CouchDB's querying structure was going to be limiting (I mean, what I wanted to do would have been super simple with SQL), but you've opened my eyes on how flexible it can be. I'll also experiment with your second method of using the same view. Much thanks! – SchattenJager Oct 27 '15 at 15:01
  • Honestly? It is still pretty limiting. What it does it does very well but it certainly doesn't suit every use case. The way to think about it is that this kind of document store doesn't really give you *querying*, what it gives you is efficient, scalable document indexing. You can generally satisfy most use cases with this (particularly if you add replication to a search index) but it's not the best data store for every scenario (much as RDBMS aren't). – Ant P Oct 27 '15 at 15:17
  • The places you're going to run into limitations for CouchDB are in heavily relational data (if you really can't denormalize to a flatter structure) and in applying DB-level constraints. In general document DBs are great in situations where relational DBs are overkill or are inefficient. – Ant P Oct 27 '15 at 15:17
  • ... which in reality is actually most situations. – Ant P Oct 27 '15 at 15:20
  • I'd just like to link https://www.youtube.com/watch?v=Jj3CaODMweM for anyone reading this with regards to relational data. It opened my eyes to how couchDB can handle relational data quite nicely (although I wouldn't expect to the scale a normal RDBS would). – webnoob Jan 19 '17 at 21:30