You are on page 1of 49

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 mvcc
write 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 # => 10
db.view("all/by_type" )['rows'].size # => 30
db.view("all/by_type",
:key => "book")['rows'].size # => 10

35
map reduce
// map // reduce
function(doc) { function(keys,values) {
emit(doc.type, doc); 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 // reduce
function(doc) { function(keys, values) {
emit( doc.master_id, var max = 0;
doc );
} for(i in values) {
if( values[i].version >
values[max].version ) {
max = i;
}
}
return(values[max]);
}

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

{ "_id": "r2d2c3",
"_rev": "2653",
"type": "comment",
"data": "..." }

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

You might also like