CouchDB views are like little scripts that run inside the database. They take each document, transform it into a (key, value) pair, and return the pairs whose keys match your query. When I first started with CouchDB, I couldn't figure out how to actually create a view — I kept thinking I was missing something. Turns out it's surprisingly straightforward.
Let's work through an example. Say you have several documents describing articles in your database:
{
"_id": "monkeys-are-awesome",
"_rev": "1534115156",
"type": "article",
"title": "Monkeys are awesome",
"posted_at": "2008-09-14T20:45:14Z",
"tags": [
"monkeys",
"awesome"
],
"status": "Live",
"author_id": "craig@barkingiguana.com",
"updated_at": "2008-09-14T21:23:59Z",
"body": "The article body would go here..."
}
You might want a view that gives you the ID and title of every document. To do this, you write a map function that accepts each document and emits the data you want back:
function(doc) {
emit(null, { 'id': doc._id, 'title': doc.title });
}
Ignore the null first argument to emit for now — that's the key used for sorting and filtering results. I'll cover it in my next post.
In practice, you'll usually want to filter by document type so you only get the results you care about. In this case, I only want article documents — comment documents might not even have a title attribute:
function(doc) {
if(doc.type == 'article') {
emit(null, { 'id': doc._id, 'title': doc.title });
}
}
Adding this view to the database is simple: you create a design document. Design documents are just regular CouchDB documents with an ID that starts with _design/ — for example, _design/articles. You can insert them using Futon, the built-in admin client, at http://localhost:5984/_utils/.
Here's the full JSON for a design document containing our titles view:
{
"_id": "_design/articles",
"_rev": "42351258",
"language": "javascript",
"views": {
"titles": {
"map": "function(doc) { emit(null, { 'id': doc._id, 'title': doc.title }); }"
}
}
}
Open Futon, navigate to your database, create a new document, and paste the view in. Once it's installed, you can browse results using the "select view" dropdown in the top right of Futon's database view. To get the raw JSON, hit the URL directly. If your database is called "blog", you'd access the view at http://localhost:5984/blog/_view/articles/titles.
A single design document can hold many views, each with a different name and returning different results. Here's one with several views, some of which use the key parameter that I'll discuss next time:
{
"_id": "_design/articles",
"_rev": "28651884",
"language": "javascript",
"views": {
"all": {
"map": "function(doc) { if(doc.type == 'article') { emit(null, doc); } }"
},
"by_author_id": {
"map": "function(doc) { if(doc.type == 'article') { emit([doc.author_id], doc); } }"
},
"by_status": {
"map": "function(doc) { if(doc.type == 'article') { emit([doc.status], doc); } }"
},
"titles": {
"map": "function(doc) { if(doc.type == 'article') { emit(null, { 'id': doc._id, 'title': doc.title }); } }"
}
}
}