March 24, 2019

Snakes on a Couch! Using Python with CouchDB, Part II-- Where do you want to eat? - page 2

The Problem

  • October 14, 2010
  • By Akkana Peck

Using those dates

But wait -- you don't want to go to the same place you had lunch yesterday. So let's use those dates for something useful. There are two approaches you might try. In either case, you'll probably want more than four restaurants, so add some more if you haven't already.

First, you could choose by number of restaurants. If you eat out every weekday, you could make an arbitrary rule that you don't want to see any place from the last week. That's easy: since your view is already sorted by date, you just want to skip the most recent five.

That means we need to do a tiny bit of arithmetic. First, notice, from the listing at the beginning of this article, that bydate/get_restaurants_by_date returns the dates in ascending order, the most recent at the end. So you'll want to skip the last five, not the first.

The total number of restaurants is tot. Previously your skip parameter was a random integer between 0 and (tot-1); so now, you'll want one between 0 and (tot-1) - 5:

# Start at a random offset into the view by date,
# but skip the 5 most recent:
restaurant_list = db.view('bydate/get_restaurants_by_date',
                          skip=random.randint(0, tot-6),

Start and End Keys

But you might want to be more specific in your exclusion, especially if you dine out irregularly: you might want to specify that you want nothing in the last week regardless of whether you've eaten at ten places in that time, or only one. CouchDB queries let you specify start and end keys. Since you only care about recent (later) dates, not earlier ones, the end key is the one you care about.

When you're using alphabetic strings or numbers, you can just pass in a parameter like endkey=42. But for dates, CouchDB uses a specific format. There's a utility routine you can use from the couchdb.scheme module:

lastweek = datetime.datetime.now() - datetime.timedelta(7)
lastweek = couchdb.schema.DateTimeField()._to_json(lastweek)

Or if you prefer, you can generate a format that works using Python's own time functions: lastweek = lastweek.strftime('%Y-%m-%d %H:%M:%S')

Of course, this query has a different total restaurant number, so you'll need to get the total again before you do your query:

rview = db.view('bydate/get_restaurants_by_date',
tot = len(rview)
rview = db.view('bydate/get_restaurants_by_date',
                skip=random.randint(0, tot-1),
                limit=1, endkey=lastweek)

If you know there's only one item, you can skip iterating over rview and just use rview.rows[0].

Updating an item

One last thing: you need an easy way to update the last-visited date when you go to one of these restaurants, or you'll never keep the database current.

Using the Restaurant class defined in Part 1, you can fetch a Restaurant object using the id from the view. Then change the last_visited date and call store():

# Definition of the Restaurant object in the Couch database:
from couchdb.schema import Document
class Restaurant(Document) :
    type = couchdb.schema.TextField()
    name = couchdb.schema.TextField()
    last_visited = couchdb.schema.DateTimeField()

# Update the last_visited date
restaurant = Restaurant.load(db, rview.rows[0].id)
restaurant.last_visited = datetime.datetime.now()

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