incubator-couchdb-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Scott Shumaker <sshuma...@gmail.com>
Subject New site powered by CouchDB - magnifeast.com
Date Fri, 07 Aug 2009 08:21:50 GMT
We've just launched our site - Magnifeast (http://www.magnifeast.com)
- which uses CouchDB as its primary persistence mechanism.

Magnifeast is a site that lets you order online from over 500
restaurants.  We're initially launching in Los Angeles, but plan to
expand to other cities soon.

CouchDB was a good fit for us because restaurant and menu data can be
very complicated - and since we're modeling real world data, it
doesn't fit any kind of rigid schema.  Even something as simple as
delivery area can be quite variable - some restaurants don't deliver
at all, others deliver to a radius, some have multiple polygonal
delivery regions (each with different fees), some deliver to a list of
cities, etc.  And menus are even more complicated.  Having a
traditional schema-oriented database (SQL) would be incredibly
frustrating and limiting.  We've been able to use CouchDB's
flexibility to express a much richer understanding of restaurants and
menus than pretty much anyone else out there.

Some technical notes:
Our site runs on Amazon EC2.  Clients don't talk to CouchDB directly -
they talk through our application servers (currently running Merb).
The app servers do authorization for reads - for example, we have
custom validation rules for various views that are addressable by the
client.  We have validation rules that run in CouchDB for writes.
Right now, since there isn't a 1-to-1 mapping between our site users
and CouchDB users, we actually append some additional fields to each
document at write-time containing information about the user role and
permissions (ideally, this could be passed as an additional parameter
to CouchDB, which could be checked in the validation function).  The
app servers also pre-save hooks that match various criteria, and might
modify the documents before saving.  It turns out that to for this to
work correctly in our case, we actually have to return a list of
deltas (fields that have been changed / removed) to the client browser
so they can be applied.  Returning the full object to the client
doesn't work because the client may have made changes to the object
since the write but before the write finished.  This is a difficult
problem to solve in general, caveat emptor.

Unlike many traditional websites, and more akin to a couchApp, the
actual HTML pages for our site are constructed on the in-browser on
the client.  The clients download templates from the server, along
with JSON data that comes from CouchDB, and use the data with the
template to assemble the page.  The templates are written in a
proprietary language called Jolt, which is javascript-based and 'Live'
- in the sense that changes in the JSON data update the page in
realtime.  Some of the pages on the site have a very interactive feel
because of this.

When the client loads data from CouchDB, the objects are loaded using
a system that can transform the JSON into instances of Javascript
classes, resolving references to other CouchDB documents (and
references to members of other document).  For example, when loading a
menu, we typically load a menu document, menu items, and menu
sections, all which are stored as top-level CouchDB documents.  These
documents all reference each other, and come in the run-time as
instantiated javascript classes, with all of the references fixed up.
A menu item can consist of dozens of internal objects as well.  If
changes were made to the menu item (for example, in our menu editing
admin tools), the menu item would be serialized back out to JSON, all
of the references to external objects replaced with pointer stubs, and
written to CouchDB.  This system effectively lets us serialize out
fairly complicated object graphs into CouchDB.

Our search page (http://www.magnifeast.com/restaurant) doesn't hit
CouchDB.  Instead, we have a custom search server, which pulls
documents from CouchDB using all_docs_by_seq, and does custom
indexing.  The searching effectively buckets couchdb documents by
various criteria, and finds the intersection of the various buckets in
responses to queries (for example, you might search for restaurants
open 'now' that deliver to your home address with Thai cuisine that
contain the search term 'Bangkok').  For textual searches, the search
server hits Ferret (similar to Lucene), and intersects the returned
result list with the other criteria.

There's a lot more going on behind the scenes.  We actually have a lot
more admin pages than regular pages - building tools so we could
efficiently get hundreds of menus and restaurants fully represented in
our system was a lot of work.  And this is just the beginning - we've
been focusing intensely on online ordering for launch, but want to
build out the site to be much more than that.

I can go into more technical details if people are interested.  Thanks
for all your hard work so far - I'm definitely glad we had an
alternative to SQL!

Scott

Mime
View raw message