Mercurial > browser-couch
view tutorial.html @ 80:042eb025bce5
Added more tutorial text.
author | Atul Varma <varmaa@toolness.com> |
---|---|
date | Mon, 20 Apr 2009 16:37:07 -0700 |
parents | 17ce8b6be452 |
children | 38abd7bc4886 |
line wrap: on
line source
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <link rel="stylesheet" type="text/css" media="all" href="css/tutorial.css" /> <title>Blog Example</title> </head> <body> <div id="content" class="documentation"> <h1>Using BrowserCouch</h1> <p>Suppose we want to add offline support for a blog. To get a database called <tt>blog-posts</tt> in BrowserCouch, you can use the following function:</p> <div class="example-code"> BrowserCouch.get('blog-posts', onRetrieveCb, new FakeStorage()); </div> <p>It's clear that the first parameter is the name of the database we want; the second parameter is the callback that will be passed the database once it's fetched.</p> <p>The third parameter specifies the engine that will be used to persistently store our database across browsing sessions. In this case we're using <tt>FakeStorage</tt>, which just stores everything non-persistently in memory for the sake of example. We could just as easily leave out the third parameter to have BrowserCouch figure out the best storage backend based on our browser's capabilities.</p> <p>If the database doesn't already exist, an empty one will be created for us. Putting blog posts into the database can be done via an <tt>onRetrieveCb()</tt> function like this:</p> <div class="example-code"> function onRetrieveCb(db) { blogDb = db; blogDb.put( [{id: 0, author: 'Myk', title: 'Burritos', content: 'Burritos are yum.'}, {id: 1, author: 'Thunder', title: 'Bacon', content: 'I like bacon.'}, {id: 2, author: 'Thunder', title: 'Beer', content: 'Beer is good too.'}], onPutCb ); }; </div> <p>Every item we put into our database needs to have an <tt>id</tt> attribute, but aside from that, the item can contain any JSON-encodable data.</p> <p>Now that we've put some data into our database, we can play around with generating views on the data using the <a href="http://en.wikipedia.org/wiki/MapReduce">MapReduce</a> mechanism. For instance, here's an ad-hoc view using only the map phase that organizes all the post titles by author:</p> <div class="example-code"> function onPutCb() { blogDb.view({ map: function(doc, emit) { emit(doc.author, doc.title); }, finished: function(result) { displayInElement(result, 'author-keyed-view'); tryAnotherView(); } }); } </div> <p>The output placed in the <tt>author-keyed-view</tt> element is:</p> <div class="example-output" id="author-keyed-view"> </div> <p>As you can see, BrowserCouch essentially iterated over all of the blog posts, passing each one to <tt>map()</tt>, along with an arbitrary function called <tt>emit()</tt>. The <tt>map()</tt> function then emitted key-value pairs which show up in the view. It's worth noting that <tt>map()</tt> can call <tt>emit()</tt> as much as it wants to; each call will add a new row to the view.</p> <p>We could also try creating another view that adds a <tt>reduce()</tt> function to group together the blog post titles with the authors:</p> <div class="example-code"> function tryAnotherView() { blogDb.view({ map: function(doc, emit) { emit(doc.author, doc.title); }, reduce: function(keys, values) { return values; }, finished: function(result) { displayInElement(result, 'author-titles-view'); tryMyView(); } }); } </div> <p>The output is as follows:</p> <div class="example-output" id="author-titles-view"> </div> <p>The <tt>reduce()</tt> mechanism is a bit harder to understand. Essentially, BrowserCouch takes all the rows generated by <tt>map()</tt> and generates a new list of key-value rows, where the value of each row is the list of all values that match the row's key. This explains what the <tt>values</tt> argument passed to <tt>reduce()</tt> is.</p> <p>The <tt>keys</tt> argument is a list of two-tuples, the first of which is the key, and the second of which is the document id that emitted the key during the map phase.</p> <p>The <tt>reduce()</tt> function is called for each unique key, and its return value is the value for its key in the final view.</p> <h1>Now You Try!</h1> <p>If your eyes are crossed right now, no worries—it took me a long time to understand exactly what MapReduce was doing, and I probably didn't explain it very well either. That said, I also found that the easiest way to understand how MapReduce worked was just to play around with making my own view.</p> <p>So, to get a better feel for how MapReduce works, you can use the text field below to try making your own view. Just press the tab key when you're done making changes to recompute the view.</p> <textarea class="example-code try-code"> function tryMyView() { blogDb.view({ map: function(doc, emit) { emit(doc.author, doc.title); }, reduce: function(keys, values) { return values; }, finished: function(result) { displayInElement(result, 'try-my-view'); } }); } </textarea> <p>Here's the output to the above view:</p> <div class="example-output" id="try-my-view"></div> <h1>Where To Go From Here</h1> <p>There's features in the API that aren't covered here, so check out the check out the <a class="intra-wiki" href="index.html#js/tests.js">annotated source code for the test suite</a> for more sample code.</p> <script src="js/ext/jquery.js"></script> <script src="js/browser-couch.js"></script> <script src="js/tutorial.js"></script> </body> </html>