Differences between revisions 4 and 5
Revision 4 as of 2009-02-23 23:47:51
Size: 4469
Editor: fw3
Comment: Redirect example
Revision 5 as of 2009-02-24 06:11:49
Size: 4917
Editor: 76-191-199-100
Comment: Added details about 'head' and 'row_info'.
Deletions are marked like this. Additions are marked like this.
Line 68: Line 68:
  listfn(true, null , req, null ); // Before the first row: head=true
  listfn(false, rows[0], req, row_info); // First row: head=false
  listfn(false, rows[1], req, row_info); // Subsequent rows...
  listfn(false, rows[2], req, row_info);
  listfn(false, null, req, row_info); // After last row: row=null
  listfn(head, null, req, null ); // Before the first row: head is non-null
  listfn(null, rows[0], req, row_info); // First row
  listfn(null, rows[1], req, row_info); // Subsequent rows...
  listfn(null, rows[2], req, row_info);
  listfn(null, null, req, row_info); // After last row: row=null
Line 75: Line 75:
List functions also have the ability to abort iteration early, which is handy for some filtering operations. The `head` parameter -- which is only passed into the first call -- contains an object with information about the view that is to be iterated over. It's much like the response object returned from a view query in the CouchDB JavaScript API; useful properties include `total_rows` and `offset`.

The `row_info` parameter contains an object with information about the iteration state. Its properties include:
* `row_number` (the current row number)
* `first_key` (the first key of the view to be listed)
* `prev_key` (the key of the row in the previous iteration)

The basics of formatting documents using show and list functions. These functions convert documents and views, respectively, into non-JSON formats. The rows of each view are processed individually, which keeps long lists from becoming memory hogs.

They are designed to be cacheable. CouchDB handles generating Etags for show and list responses.

Show and list functions are side effect free and idempotent. They can not make additional HTTP requests against CouchDB. Their purpose is to render JSON documents in other formats.

Showing Documents

Show functions are stored in your design document, under the shows key. Here's an example set of show functions:

{
"_id" : "_design/examples",
"shows" : {
  "posts" : "function(doc, req) {... return responseObject;}",
  "people" : "function(doc, req) { ... }"
}

Assuming these functions were in a design document named "examples" in a database named "db", they could be queried like this:

GET /db/_show/examples/posts/somedocid

GET /db/_show/examples/people/otherdocid

GET /db/_show/examples/people/otherdocid?format=xml&details=true

The show function is run with two arguments. The first is the document corresponding to the requested docid, and the second describes the HTTP request's query string, Accept headers, and other per-request information. The function returns an object describing its HTTP response.

The request and response objects are of the same format used by _external functions, as documented in ExternalProcesses.

Listing Views

List functions are stored under the lists key of a design document. Here's an example design doc with list functions, in addition to views:

{
"_id" : "_design/examples",
"views" {
  "posts-by-date" : "function(doc){...}",
  "posts-by-tag" : "function(doc){...}",
  "people-by-name" : "function(doc) {...}"
},
"lists" : {
  "index-posts" : "function(head, row, req, row_info) {...}",
  "browse-people" : "function(head, row, req, row_info) { ... }"
}

These lists are run by querying URLs like:

GET /db/_list/examples/index-posts/posts-by-date?descending=true&limit=10

GET /db/_list/examples/index-posts/posts-by-tag?key="howto"

GET /db/_list/examples/browse-people/people-by-name?startkey=["a"]&limit=10

[As above, we assume the database is named "db" and the design doc "examples".]

A list function has a more interesting signature, as it is passed the head of the view on first invocation, then each row in turn, then called one more time for the tail of the view. The function should check the head and row parameters to identify which state it's being called in; the sequence of calls to listfn, for a view with three rows, would look like:

  listfn(head, null,    req, null    );  // Before the first row: head is non-null
  listfn(null, rows[0], req, row_info);  // First row
  listfn(null, rows[1], req, row_info);  // Subsequent rows...
  listfn(null, rows[2], req, row_info);
  listfn(null, null,    req, row_info);  // After last row: row=null

The head parameter -- which is only passed into the first call -- contains an object with information about the view that is to be iterated over. It's much like the response object returned from a view query in the CouchDB JavaScript API; useful properties include total_rows and offset.

The row_info parameter contains an object with information about the iteration state. Its properties include: * row_number (the current row number) * first_key (the first key of the view to be listed) * prev_key (the key of the row in the previous iteration)

Example list function:

function(head, row, req, row_info) {
  if (head) {
    return "<p>head: "+JSON.stringify(head)+"</p><ul>"";
  } else if (row) {
    return "<li>"+JSON.stringify(row)+"</li>";
  } else {
    return "</ul><h4>the tail</h4>"
  }
}

Other Fun Things

Stopping iteration in a `_list`

If you want to terminate iteration of a _list early you can return a {stop: true} JSON object from any of the calls to the function that include a row object.

Sending a Redirect

In the call to _show or when _list is called with a head object you can control the headers and status code sent to the client. An example of this would be to send a redirect notification.

function(doc)
{
    return {"code": 302, "body": "See other", "headers": {"Location": "/"}};
}

function(head, row, req, row_info) {
  if (head) {
    return {"code": 302, "body": "See other", "headers": {"Location": "/"}};
  } else if (row) {
    return {stop: true};
  } else {
    return "."
  }
}

Hopefully this is enough to get started. For a more complete set of examples, see the CouchDB test suite, especially show_documents.js and list_views.js