2. What
we ll
talk
about
• Working
with
JSON
documents
• Run8me-‐driven
paCerns
for
• linking
between
documents
• embedding
data
• fetching
mul8ple
documents
2
4. Couchbase
Server
is
a
Document
Database
hCp://mar8nfowler.com/bliki/AggregateOrientedDatabase.html
This synergy between the programming model and the distribution model is very valuable.
It allows the database to use its knowledge of how the application programmer clusters the data
to help performance across the cluster.
4
5. Document
Database
o::1001
{
uid:
ji22jd,
customer:
Ann,
line_items:
[
{
sku:
0321293533,
quan:
3,
unit_price:
48.0
},
{
sku:
0321601912,
quan:
1,
unit_price:
39.0
},
{
sku:
0131495054,
quan:
1,
unit_price:
51.0
}
],
payment:
{
type:
Amex,
expiry:
04/2001,
last5:
12345
}
}
• Easy
to
distribute
data
• Makes
sense
to
applica8on
programmers
5
6. JSON
Documents
• Map
more
closely
to
objects
or
en88es
• CRUD
Opera8ons,
lightweight
schema
myDocument = {!
fields : [ with basic types , 3.14159, true],!
like : your favorite language. ,!
status : {!
apis : true,!
databases : document }!
}!
• Stored
under
a
unique
iden8fier
key
client.set( mydocumentid , myDocument);!
mySavedDocument = client.get( mydocumentid );!
6
7. Object
to
JSON
back
to
Object
User
Object
u::jasdeep@couchbase.com
{
set()
string
uid
uid :
123456,
string
firstname
firstname :
jasdeep ,
string
lastname
lastname :
Jaitla ,
int
age
age :
22,
favorite_colors :
[ blue ,
black ],
array
favorite_colors
email :
jasdeep@couchbase.com
string
email
}
User
Object
u::jasdeep@couchbase.com
{
get()
string
uid
uid :
123456,
string
firstname
firstname :
jasdeep ,
string
lastname
lastname :
Jaitla ,
int
age
age :
22,
favorite_colors :
[ blue ,
black ],
array
favorite_colors
email :
jasdeep@couchbase.com
string
email
}
7
8. Meta
+
Document
Body
{
Document
"brewery":
"New
Belgium
Brewing",
user data,
"name":
"1554
Enlightened
Black
Ale",
can be anything
"abv":
5.5,
"descrip8on":
"Born
of
a
flood...",
"category":
"Belgian
and
French
Ale",
"style":
"Other
Belgian-‐Style
Ales",
"updated":
"2010-‐07-‐22
20:00:20"
}
unique ID
vintage date format from an SQL dump
{
>_<
"id"
:
"beer_Enlightened_Black_Ale ,
Metadata
...
identifier,
{
expiration, etc
8
9. No
More
ALTER
table
• No
More
alter
table
• More
produc8ve
developers!
• Emergent
schema
• Schema
driven
by
code
9
11. Real8me
Interac8ve
CRUD
• Requirement:
high-‐performance
with
high-‐
concurrency
and
dynamic
scale
• Key/value
API
is
the
interac8ve
low-‐latency
path
11
12. Couchbase
Basic
Opera8ons
• get
(key)
–
Retrieve
a
document
• set
(key,
value)
–
Store
a
document,
overwrites
if
exists
• add
(key,
value)
–
Store
a
document,
error/excep8on
if
exists
• replace
(key,
value)
–
Store
a
document,
error/excep8on
if
doesn t
exist
• cas
(key,
value,
cas)
–
Compare
and
swap,
mutate
document
only
if
it
hasn t
changed
while
execu8ng
this
opera8on
12
13. Couchbase
Basic
Opera8ons
(cont d)
Atomic
Counters
are
a
special
structure
in
Couchbase,
they
are
executed
in
order
and
are
Posi8ve
Integer
Values
• set
(key,
value)
–
Use
set
to
ini8alize
the
counter
• cb.set( my_counter ,
1)
• incr
(key)
–
Increase
an
atomic
counter
value,
default
by
1
• cb.incr( my_counter )
#
now
it s
2
• decr
(key)
–
Decrease
an
atomic
counter
value,
default
by
1
• cb.decr( my_counter )
#
now
it s
1
13
14. Simple
Example
in
Ruby
#
example.rb
#
user.rb
require
rubygems
require
./user.rb
require
couchbase
u1
=
User.new({
class
User
:email
=>
jasdeep@scalabl3.com ,
aCr_accessor
:name,
:email,
:8tle,
:twiCer
:name
=>
Jasdeep
Jaitla ,
def
ini8alize(aCr
=
{})
aCr.each
do
|name,
value|
:8tle
=>
Scalability
Sherpa ,
seCer
=
"#{name}="
next
unless
respond_to?(seCer)
:twiCer
=>
@scalabl3
send(seCer,
value)
end
})
end
u1.save
def
save
C
=
Couchbase.bucket
C.
set(@email.downcase,
self.to_json)
end
end
14
15. Run8me
Driven
Schema
• What s
in
the
database
looks
more
like
your
code
• Thinking
about
throughput,
latency,
update
and
read
paCerns
is
the
new
data
modeling
• Data
flows
get
more
aCen8on
than
data
at
rest
• When
should
I
split
a
data-‐structure
into
mul8ple
documents?
• Generally
the
more
useful
your
document
is
as
a
standalone
en8ty,
the
beCer.
• Documents
that
grow
without
bound
are
bad
15
17. Let s
Add
Comments
and
Ra8ngs
to
the
Beer
• Challenge
linking
documents
together
• Whether
to
grow
an
exis8ng
document
or
store
independent
documents
• No
transac8onality
between
documents!
good w/ burgers
{
"brewery":
"New
Belgium
Brewing",
I give that a 5!
"name":
"1554
Enlightened
Black
Ale",
"abv":
5.5,
"descrip8on":
"Born
of
a
flood...",
tastes like
"category":
"Belgian
and
French
Ale",
college!
"style":
"Other
Belgian-‐Style
Ales",
"updated":
"2010-‐07-‐22
20:00:20"
}
17
18. Let s
Add
Comments
and
Ra8ngs
to
the
Beer
• Put
comments
in
their
own
documents
• And
add
the
ra8ngs
to
the
beer
document
itself.
{
{
"type":
"comment",
"brewery":
"New
Belgium
Brewing",
"about_id":
"beer_Enlightened_Black_Ale",
"name":
"1554
Enlightened
Black
Ale",
"user_id":
525,
"abv":
5.5,
"text":
"tastes
like
college!",
"descrip8on":
"Born
of
a
flood...",
"updated":
"2010-‐07-‐22
20:00:20"
"category":
"Belgian
and
French
Ale",
}
"style":
"Other
Belgian-‐Style
Ales",
"updated":
"2010-‐07-‐22
20:00:20",
ra8ngs
:
{
I give that a 5!
525
:
5,
30
:
4,
1044
:
2
},
comments
:
[
f1e62 ,
6ad8c
]
}
18
19.
{
"type":
"user",
{
"user_id":
525,
"brewery":
"New
Belgium
Brewing",
"name":
"Chris",
"name":
"1554
Enlightened
Black
Ale",
"email":
"jchris@couchbase.com"
"abv":
5.5,
}
"descrip8on":
"Born
of
a
flood...",
"category":
"Belgian
and
French
Ale",
"style":
"Other
Belgian-‐Style
Ales",
"updated":
"2010-‐07-‐22
20:00:20",
ra8ngs
:
{
I give tha
t a 5!
525
:
5,
30
:
4,
{
},
1044
:
2
"type":
"comment",
comments
:
[
"about_id":
"beer_Enlightened_Black_Ale",
f1e62 ,
"user_id":
525,
6ad8c
"text":
"tastes
like
college!",
]
"updated":
"2010-‐07-‐22
20:00:20"
}
}
20. Do
it:
save
the
comment
document
• Set
at
the
id
f1e62
client.set( f1e62 ,{!
!
! create a new
"type":
"comment",
!
!
"about_id”:"beer_Enlightened_Black_Ale",
document
!
"user_id":
525,
!
"text":
"tastes
like
college!",
!
"updated":
"2010-‐07-‐22
20:00:20"
{
!
"id":
"f1e62"
! }
});!
20
21. Link
between
comments
and
beers
{
"type":
"comment",
{
"about_id":
"beer_Enlightened_Black_Ale",
"brewery":
"New
Belgium
Brewing",
link to
"user_id":
525,
"name":
"1554
Enlightened
Black
Ale",
beer
"text":
"tastes
like
college!",
"abv":
5.5,
"updated":
"2010-‐07-‐22
20:00:20"
"descrip8on":
"Born
of
a
flood...",
}
"category":
"Belgian
and
French
Ale",
"style":
"Other
Belgian-‐Style
Ales",
"updated":
"2010-‐07-‐22
20:00:20",
ra8ngs
:
{
525
:
5,
{
"id":
"f1e62"
30
:
4,
1044
:
2
},
}
comment_ids
:
[
f1e62 ,
link to
6ad8c
]
comments
}
21
22. How
to:
look
up
comments
from
a
beer
• SERIALIZED
LOOP
beer = client.get( beer:A_cold_one );!
beer.comment_ids.each { |id|!
comments.push(client.get(id));!
}!
• FAST
MULTI-‐KEY
LOOKUP
beer = client.get( beer:A_cold_one );!
comments = client.multiGet(beer.comment_ids)!
!
• ASYNC
VIEW
QUERY
comments = client.query( myapp , by_comment_on ,!
{:key => beer:A_cold_one });!
!
figure
hCp://www.ibm.com/developerworks/webservices/library/ws-‐sdoarch/
22
23. How
to:
add
a
ra8ng
to
a
beer
• Other
users
are
ra8ngs
beers
also,
so
we
use
a
CAS
update
– we
don t
want
to
accidentally
overwrite
another
users
ra8ng
that
is
being
saved
at
the
same
8me
as
ours
• Best
prac8ce
is
to
use
a
lambda
so
the
client
can
retry
cb.cas("mykey") do |doc| !
doc["ratings"][current_user.id] = my_rating
doc!
end!
!
Actor
1
Actor
2
Success
CAS
mismatch
&
retry
Couchbase
Server
23
24. Object
Graph
With
Shared
Interac8ve
Updates
• Challenge:
higher
level
data
structures
• Objects
shared
across
mul8ple
users
• Mixed
object
sets
(upda8ng
some
private
and
some
shared
objects)
figure
hCp://www.ibm.com/developerworks/webservices/library/ws-‐sdoarch/
24
25. Get
With
Lock
(GETL)
• O{en
referred
to
as
GETL
• Pessimis8c
concurrency
control
• Locks
have
a
short
TTL
• Locks
released
with
CAS
opera8ons
• Useful
when
working
with
object
graphs
25