relaxing with couchdb

will leinweber will@bitfission.com

acts_as_conference 2009
1

2

this talk: why & how

3

what is couchdb?

4

document database no schema

5

erlang concurrent scalable

6

built for the web restful json

7

json
{ "title": "A Brief History of Slinkies", "chapters": [ { "title": "Sorta like a spring", "text": "Round and metal..." }, { "title": "Stairs", "text": "They can go down, but not up" }], "_id": "4b859...", "_rev": "3280991488" }

8

multi version concurrency control no locking
locking write mvcc reads

9

add only never in a bad state

10

incremental replication eventual consistency winning documents

11

couchdb only apps javascript + html

12

multiple databases for a single app

13

integrate with full text search

14

file attachment

15

views (not queries)

16

stored as design documents

17

view server javascript (spidermonkey) ruby and python too

18

map reduce (optional)

19

goes through each document very slow

20

map step emits keys value pairs

21

persisted index keeps track of changes

22

keep your views fresh

23

http benefits

24

cacheable load balancers

25

easy interface understand and implement

26

getting started

27

install couch from svn head get erlang, spidermonkey, icu

28

gem install jchris-couchrest lightweight api wrapper

29

db = CouchRest.database!("http://localhost:5984/books") response = db.save(:title => "recipes") # => {"rev"=>"2351730874", "id"=>"07cb62...", "ok"=>true} doc = db.get response["id"] # => {"title"=>"recipes", "_id"=>"07cb62...", "_rev"=>"2351730874"}

30

$ curl http://localhost:5984/books/07cb6232593b61dd022d1c05b1c7deac {"_id":"07cb6232593b61dd022d1c05b1c7deac","_rev":"2351730874", "title":"recipes"}

31

doc["title"] = "cook book" doc.save # => true db.get response["id"] # => {"title"=>"cook book", "_id"=>"07cb623...", "_rev"=>"3767210759"} doc.destroy # => true db.get response["id"] # => RestClient::ResourceNotFound

32

33

simple view
function(doc) { if (doc.type == "book") { emit(null, doc); } db.view("books/all") }

34

view with keys
function(doc) { emit(doc.type, doc); }
db.view("books/all" )['rows'].size db.view("all/by_type" )['rows'].size db.view("all/by_type", :key => "book")['rows'].size # => 10 # => 30 # => 10

35

map reduce

// map function(doc) { emit(doc.type, doc); }

// reduce
function(keys,values) { return(values.length); }

db.view("count/by_type") # => {"rows"=> {"value"=>3, "key"=>nil}]} db.view("count/by_type", :group => true) # => {"rows"=>[{"value"=>10, "key"=>"article"}, {"value"=>10, "key"=>"book"}, {"value"=>10, "key"=>"user"}]} db.view("count/by_type", :key => "book") # => {"rows"=>[{"value"=>10, "key"=>nil}]}

36

versioning
{ "title": "Slinkies!", "version": 4, "master_id": "3de0c...", "_id": "af322...", "chapters": [...] }

37

versioning
// map function(doc) { emit( doc.master_id, doc ); } // reduce function(keys, values) { var max = 0; for(i in values) { if( values[i].version > values[max].version ) { max = i; } } return(values[max]); }

38

view collation
{ "_id": "_rev": "type": "data": "abc012", "2387", "post", "..." } { "_id": "_rev": "type": "data": "_id": "_rev": "type": "data": "def345", "2387", "comment", "..." } "r2d2c3", "2653", "comment", "..." }

{

39

view collation
function(doc) { if (doc.type == "post") { emit([doc._id, 0], doc); } else if (doc.type == "comment") { emit([doc.post, 1], doc); } }

40

CouchRest::Model being removed from couchrest
class Book < CouchRest::Model key_accessor :title, :text, :author cast :author, :as => "User" timestamps! end
# config/environment.rb CouchRest::Model.default_database = CouchRest.database!("appname-#{ENV['RAILS_ENV']}")

41

others langalex-couch_potato active couch

42

downsides

43

moving target

44

arbitrary queries are slow

45

lack of supporting tools

46

loss of intuition

47

what you should do next

48

thanks!

49

Sign up to vote on this title
UsefulNot useful