May 26, 2018

Snakes on a Couch! Using Python with CouchDB - page 2

Diving Right In

  • September 23, 2010
  • By Akkana Peck

How do you get documents back out of a Couch database? By defining a view using Javascript MapReduce queries.

You've probably heard of MapReduce. It's some fancy patented thing Google uses to index the whole web, right?

Don't panic. The concept behind MapReduce is simple. First you have a map function that decides, for each document in the database, "Does this document match?"

The advantage of this approach is that the map function can be very simple -- and it's easy to spread the workload over many different machines. You end up with a few short lists of items which you can combine with a reduce function.

Let's stick with just map functions for now. Here's a simple one. Remember, this is Javascript, not Python: don't try to type it into the Python interpreter.

  if (doc.type == 'restaurant') {
    emit(doc.name, null)

A map function produces a list of documents matching its criteria. In this case, we call emit(key, value) on anything that matches: anything with type "restaurant".

The key is what Couch will use for sorting. So restaurants will be returned sorted alphabetically by name. The second argument is any additional information you want to make available to the caller; in this case, we don't need anything extra.

Setting map functions in Python uses a somewhat complicated syntax. First define a string containing the Javascript map function:

retrieve_mapfn = """function(doc)
  if (doc.type == 'restaurant') {
    emit(doc.name, null);

Add it to the database using this syntax:

design = { 'views': {
           'get_restaurants': {
              'map': retrieve_mapfn
         } }
db["_design/restaurantlist"] = design

You're storing your map function in a document named "_design/restaurantlist". If you check Futon now, you'll see the new document. And you can even test your view through Futon, using the menu in the upper right (Figure 3).

<em>figure 3</em>
figure 3

This complex nested syntax arises because you're actually creating an object using JSON -- JavaScript Object Notation -- which is what CouchDB uses under the hood. Fortunately the nature of map/reduce queries mean they'll usually be fairly small and simple.

Using your view

How do you use the query to get a list of restaurants? Create a view with the name of your app combined with the name of the map function query:

restaurant_list = db.view('restaurantlist/get_restaurants')

for r in restaurant_list :
    print r.key

Voil´┐Ż! A list of restaurants in the database. Try adding a few of your favorite restaurants to verify that it works.

Restaurant(type="restaurant", name="Pasta Market", last_visited=datetime.date(2010, 9, 20)).store(db)
Restaurant(type="restaurant", name="Seto", last_visited=datetime.date(2010, 8, 10)).store(db)
Restaurant(type="restaurant", name="Bollywood Cafe", last_visited=datetime.date(2010, 9, 5)).store(db)

restaurant_list = db.view('restaurantlist/get_restaurants')
for r in restaurant_list :
    print r.key
You'll see:
Alice's Restaurant
Bollywood Cafe
Pasta Market

What if you want to sort by date? Make a map function that emits the date as the sort key:

date_mapfn = """function(doc)
  if (doc.type == 'restaurant') {
    emit(doc.last_visited, doc.name);

Notice that this time, the function also emits a value: doc.name, the name of the restaurant. You can use that value when looping over the view results.

Couch makes it slightly tricky to change an existing design document, so for now, just make a new one called _design/bydate:

design = { 'views': {
           'get_restaurants_by_date': {
              'map': date_mapfn
         } }
db["_design/bydate"] = design
restaurant_list = db.view('bydate/get_restaurants_by_date')
for r in restaurant_list :
    print r.value, "-- Last visited:", r.key

Run it:

Alice's Restaurant -- Last visited: 1965-11-25T00:00:00Z
Seto -- Last visited: 2010-08-10T00:00:00Z
Bollywood Cafe -- Last visited: 2010-09-05T00:00:00Z
Pasta Market -- Last visited: 2010-09-20T00:00:00Z

In part 2, you'll see how to use reduce functions, and how to put it all together into an app.

Akkana Peck is a freelance programmer and writer, amateur photographer and the author of the book Beginning GIMP: From Novice to Professional. She's also a control freak who loves fiddling with devices and making them do things they aren't supposed to be able to do.

Most Popular LinuxPlanet Stories

We have made updates to our Privacy Policy to reflect the implementation of the General Data Protection Regulation.