Squire: A polyglot application combining Neo4j, MongoDB, Ruby and Scala @ FOSDEM GraphDevRoom 2013
Practical Ruby Projects with MongoDB - Ruby Kaigi 2010
-
Upload
alex-sharp -
Category
Technology
-
view
2.466 -
download
1
Transcript of Practical Ruby Projects with MongoDB - Ruby Kaigi 2010
![Page 1: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/1.jpg)
PRACTICAL
PROJECTS WITH
![Page 2: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/2.jpg)
WHO AM I?
Alex SharpLead Developer at OptimisDev
@ajsharp (on the twitters)
alexjsharp.com (on the ‘tubes)
github.com/ajsharp (on the ‘hubs)
![Page 3: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/3.jpg)
MAJOR POINTS
• Making the case for Mongo
• Brief intro to MongoDB
• Practical Projects
![Page 4: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/4.jpg)
MAKING THE CASE
![Page 5: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/5.jpg)
THE PROBLEMS OF SQL
![Page 6: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/6.jpg)
A BRIEF HISTORY OF SQL
• Developed at IBM in early 1970’s.
• Designed to manipulate and retrieve data stored in relational databases
![Page 7: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/7.jpg)
A BRIEF HISTORY OF SQL
• Developed at IBM in early 1970’s.
• Designed to manipulate and retrieve data stored in relational databases
this is a problem
![Page 8: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/8.jpg)
WE DON’T WORK WITH DATA...
![Page 9: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/9.jpg)
WE WORK WITH OBJECTS
![Page 10: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/10.jpg)
WE DON’T CARE ABOUT
STORING DATA
![Page 11: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/11.jpg)
WE CARE ABOUT PERSISTING STATE
![Page 12: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/12.jpg)
DATA != OBJECTS
![Page 13: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/13.jpg)
THEREFORE...
![Page 14: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/14.jpg)
BOLD STATEMENT FORTHCOMING...
![Page 15: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/15.jpg)
relational DBs are an antiquated tool for our
needs
![Page 16: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/16.jpg)
OK, SO WHAT?
Relational schemas are designed to store and query data,
not persist objects.
![Page 17: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/17.jpg)
To reconcile this mismatch, we have
ORM’s
![Page 18: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/18.jpg)
Object Relational Mappers
![Page 19: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/19.jpg)
ORMs enable us to create a mapping between our
native object model
and a relational schema
![Page 20: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/20.jpg)
We’re forced to create
relationships for data
when what we really want is
properties for objects.
![Page 21: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/21.jpg)
THIS IS NOT EFFICIENT
![Page 22: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/22.jpg)
A WEIRD EXAMPLE...
![Page 23: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/23.jpg)
@alex = Person.new( :name => "alex", :stalkings => [ Friend.new("Jim"), Friend.new("Bob")])
![Page 24: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/24.jpg)
<Person:0x10017d030 @name="alex", @stalkings= [#<Friend:0x10017d0a8 @name="Jim">, #<Friend:0x10017d058 @name="Bob">]>
NATIVE RUBY OBJECT
![Page 25: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/25.jpg)
@alex.to_json=> { name: "alex", stalkings: [{ name: "Jim" }, { name: "Bob" }] }
JSON REPRESENTATION
![Page 26: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/26.jpg)
Relational Schema Representation
people: - name
stalkings: - name - stalker_id - stalkee_id
![Page 27: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/27.jpg)
What!?
SQL Schema Representationpeople: - name
stalkings: - name - stalker_id - stalkee_id
![Page 28: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/28.jpg)
Ruby -> JSON -> SQL
@alex.to_json{ name: "alex", stalkings: [{ name: "Jim" }, { name: "Bob" }] }
<Person:0x10017d030 @name="alex", @stalkings= [#<Friend:0x10017d0a8 @name="Jim">, #<Friend:0x10017d058 @name="Bob">]>
Ruby
JSON
SQLpeople: - name
stalkings: - name - stalker_id - stalkee_id
![Page 29: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/29.jpg)
Ruby -> JSON -> SQL
@alex.to_json{ name: "alex", stalkings: [{ name: "Jim" }, { name: "Bob" }] }
<Person:0x10017d030 @name="alex", @stalkings= [#<Friend:0x10017d0a8 @name="Jim">, #<Friend:0x10017d058 @name="Bob">]>
Ruby
JSON
SQLFeels like we’re working
too hard here
people: - name
stalkings: - name - stalker_id - stalkee_id
![Page 30: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/30.jpg)
You’re probably thinking...
“SQL isn’t that bad”
![Page 31: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/31.jpg)
Maybe.
![Page 32: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/32.jpg)
But we can do better.
![Page 33: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/33.jpg)
THE IDEAL PERSISTENCE LAYER:
![Page 34: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/34.jpg)
THE IDEAL PERSISTENCE LAYER:
1. To persist objects in their native state
![Page 35: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/35.jpg)
THE IDEAL PERSISTENCE LAYER:
1. To persist objects in their native state
2. Does not interfere w/ application development
![Page 36: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/36.jpg)
THE IDEAL PERSISTENCE LAYER:
1. To persist objects in their native state
2. Does not interfere w/ application development
3. Provides features needed to build modern web apps
![Page 37: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/37.jpg)
MONGO TO THE RESCUE!
![Page 38: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/38.jpg)
WHAT IS MONGODB?
mongodb is a high-performance, schema-less, scalable, document-
oriented database
![Page 39: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/39.jpg)
STRENGTHS
![Page 40: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/40.jpg)
SCHEMA-LESS
![Page 41: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/41.jpg)
SCHEMA-LESS• Great for rapid, iterative, agile development
![Page 42: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/42.jpg)
SCHEMA-LESS• Great for rapid, iterative, agile development
• Makes things possible that in an RDBMS are either
a. impossibly hard
b. virtually impossible
c. way harder than they should be
![Page 43: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/43.jpg)
DOCUMENT-ORIENTED
![Page 44: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/44.jpg)
DOCUMENT-ORIENTED
• Mongo stores documents, not rows
• documents are stored as binary json
![Page 45: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/45.jpg)
DOCUMENT-ORIENTED
• Mongo stores documents, not rows
• documents are stored as binary json
• Rich, familiar query syntax
![Page 46: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/46.jpg)
DOCUMENT-ORIENTED
• Mongo stores documents, not rows
• documents are stored as binary json
• Rich, familiar query syntax
• Embedded documents eliminate many modeling headaches
![Page 47: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/47.jpg)
sample mongo document
{'status': 500, 'request_method': 'post', 'controller_action': 'notes#create', 'user': {'first_name': 'John', 'last_name': 'Doe'}}
QUERY EXAMPLES
![Page 48: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/48.jpg)
logs.find('status' => 500)
# SQL equivalent:# select * from logs WHERE logs.status = 500
QUERY EXAMPLES
{'status': 500, 'request_method': 'post', 'controller_action': 'notes#create', 'user': {'first_name': 'John', 'last_name': 'Doe'}}
![Page 49: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/49.jpg)
logs.find('status' => 500, 'user.last_name' => 'Doe')
# SQL equivalent: none
QUERY EXAMPLES
{'status': 500, 'request_method': 'post', 'controller_action': 'notes#create', 'user': {'first_name': 'John', 'last_name': 'Doe'}}
![Page 50: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/50.jpg)
logs.find('status' => 500, 'user.last_name' => 'Doe')
QUERY EXAMPLES
user is an embedded document
{'status': 500, 'request_method': 'post', 'controller_action': 'notes#create', 'user': {'first_name': 'John', 'last_name': 'Doe'}}
![Page 51: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/51.jpg)
logs.find('status' => 500, 'user.last_name' => 'Doe')
QUERY EXAMPLES
in sql, we would have JOIN-ed to the ‘users’ table to do this query
![Page 52: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/52.jpg)
# also works w/ regexlogs.find('request_method' => /p/i)
# SQL equivalent:# select * from logs where request_method LIKE %p%
QUERY EXAMPLES
{'status': 500, 'request_method': 'post', 'controller_action': 'notes#create', 'user': {'first_name': 'John', 'last_name': 'Doe'}}
![Page 53: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/53.jpg)
BIG DATA
![Page 54: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/54.jpg)
BIG DATA
• Built to scale horizontally into the cloudz
![Page 55: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/55.jpg)
BIG DATA
• Built to scale horizontally into the cloudz
• Auto-sharding
• set a shard-key, a cluster of nodes, go
![Page 56: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/56.jpg)
FAST WRITES
![Page 57: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/57.jpg)
FAST WRITES
• In-place updates
• i.e. upsert
![Page 58: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/58.jpg)
FAST WRITES
• In-place updates
• i.e. upsert
• Lot’s of db commands for fast updates
• $set, $unset, $inc, $push
![Page 59: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/59.jpg)
UPSERT
• Update if present, insert otherwise
• careful: update does a hard replace of the entire document
# initial insertposts.save(:title => 'my post', :body => '...')
# update-in-place "upsert"posts.save(:_id => 'post_id', :title => 'new title', :body => '...')
![Page 60: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/60.jpg)
AGGREGATION
Map/reduce for aggregation
![Page 61: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/61.jpg)
// mapfunction() { emit(this.controller_action, { count: 1 });}
// reducefunction(key, values) { var sum = 0; values.forEach(function(doc) { sum += doc.count; }); return { count: sum };}
AGGREGATION
![Page 62: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/62.jpg)
FAST READS
Optimize reads with indexes, just like an rdbms
![Page 63: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/63.jpg)
# index is only created if it does not existlogs.create_index('status')
# can index on embedded documentslogs.create_index('user.first_name')
# create compound indexeslogs.create_index( [['user.first_name', 1], ['user.last_name', 1]])
![Page 64: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/64.jpg)
WEAKNESSES
![Page 65: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/65.jpg)
JOINS
nope.
![Page 66: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/66.jpg)
MULTI-DOCUMENTTRANSACTIONS
no-sir-ee.
![Page 67: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/67.jpg)
RELATIONAL INTEGRITY
not a chance.
![Page 68: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/68.jpg)
PRACTICAL PROJECTS
![Page 69: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/69.jpg)
1. Accounting Application
2. Capped Collection Logging
3. Blogging app
![Page 70: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/70.jpg)
GENERAL LEDGER ACCOUNTING APPLICATION
![Page 71: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/71.jpg)
THE OBJECT MODELledger
transactions
entries
*
*
![Page 72: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/72.jpg)
THE OBJECT MODEL
# Credits Debits
1 { :account => “Cash”, :amount => 100.00 }
{ :account => “Notes Pay.”, :amount => 100.00 }
2 { :account => “A/R”, :amount => 25.00 }
{ :account => “Gross Revenue”, :amount => 25.00 }
Ledger Entries
{
Line item {
Line item
![Page 73: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/73.jpg)
THE OBJECT MODEL
![Page 74: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/74.jpg)
THE OBJECT MODEL
• Each ledger line item belongs to a ledger
![Page 75: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/75.jpg)
THE OBJECT MODEL
• Each ledger line item belongs to a ledger
• Each ledger line item has two (or more) ledger entries
• must have at least one credit and one debit
• credits and debits must balance
![Page 76: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/76.jpg)
THE OBJECT MODEL
• Each ledger line item belongs to a ledger
• Each ledger line item has two (or more) ledger entries
• must have at least one credit and one debit
• credits and debits must balance
• These objects must be transactional
![Page 77: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/77.jpg)
@debit = Entry.new(:account => 'Cash', :amount => 100.00, :type => 'credit')
@credit = Entry.new(:account => 'Notes Pay.', :amount => 100.00, :type => 'debit')
@line_item = LineItem.new(:ledger_id => 1, :entries => [@debit, @credit])
SQL-BASED OBJECT MODEL
![Page 78: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/78.jpg)
@debit = Entry.new(:account => 'Cash', :amount => 100.00, :type => 'credit')
@credit = Entry.new(:account => 'Notes Pay.', :amount => 100.00, :type => 'debit')
@line_item = LineItem.new :ledger_id => 1, :entries => [@debit, @credit]
In a relational schema, we need a database transaction to ensure multi-row atomicity
SQL-BASED OBJECT MODEL
![Page 79: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/79.jpg)
@debit = Entry.new(:account => 'Cash', :amount => 100.00, :type => 'credit')
@credit = Entry.new(:account => 'Notes Pay.', :amount => 100.00, :type => 'debit')
@line_item = LineItem.new :ledger_id => 1, :entries => [@debit, @credit]
Because we need to create 3 new records in the database here
SQL-BASED OBJECT MODEL
![Page 80: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/80.jpg)
MONGO-FIED MODELING@line_item = LineItem.new(:ledger_id => 1, :entries => [ {:account => 'Cash', :type => 'debit', :amount => 100}, {:account => 'Notes pay.', :type => 'debit', :amount => 100} ])
![Page 81: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/81.jpg)
MONGO-FIED MODELING
This is the perfect case for embedded documents.
@line_item = LineItem.new(:ledger_id => 1, :entries => [ {:account => 'Cash', :type => 'debit', :amount => 100}, {:account => 'Notes pay.', :type => 'debit', :amount => 100} ])
![Page 82: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/82.jpg)
MONGO-FIED MODELING
We will never have more than a few entries (usually two)
@line_item = LineItem.new(:ledger_id => 1, :entries => [ {:account => 'Cash', :type => 'debit', :amount => 100}, {:account => 'Notes pay.', :type => 'debit', :amount => 100} ])
![Page 83: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/83.jpg)
MONGO-FIED MODELING@line_item = LineItem.new(:ledger_id => 1, :entries => [ {:account => 'Cash', :type => 'debit', :amount => 100}, {:account => 'Notes pay.', :type => 'debit', :amount => 100} ])
Embedded docs are perfect for “contains” many relationships
![Page 84: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/84.jpg)
MONGO-FIED MODELING
DB-level transactions no-longer needed.Mongo has single document atomicity.
@line_item = LineItem.new(:ledger_id => 1, :entries => [ {:account => 'Cash', :type => 'debit', :amount => 100}, {:account => 'Notes pay.', :type => 'debit', :amount => 100} ])
![Page 85: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/85.jpg)
WINS
![Page 86: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/86.jpg)
WINS
•Simplified, de-normalized data model
•Objects modeled differently in Mongo than SQL
![Page 87: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/87.jpg)
WINS
•Simplified, de-normalized data model
•Objects modeled differently in Mongo than SQL
•Simpler data model + no transactions = WIN
![Page 88: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/88.jpg)
LOGGING WITH CAPPED
COLLECTIONS
![Page 89: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/89.jpg)
BASELESS STATISTIC
95% of the time logs are NEVER used.
![Page 90: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/90.jpg)
MOST LOGS ARE ONLY USED WHEN SOMETHING GOES
WRONG
![Page 91: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/91.jpg)
• Fixed-sized, limited operation, auto age-out collections (kinda like memcached, except persistent)
• Fixed insertion order
• Super fast (faster than normal writes)
• Ideal for logging and caching
CAPPED COLLECTIONS
![Page 92: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/92.jpg)
GREAT. WHAT’S THAT MEAN?
We can log additional pieces of arbitrary data effortlessly due to Mongo’s schemaless nature.
![Page 93: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/93.jpg)
THIS IS AWESOME
![Page 94: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/94.jpg)
CAPTURE.QUERY.
ANALYZE. PROFIT.
![Page 95: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/95.jpg)
ALSO A REALLY HANDY TROUBLESHOOTING
TOOL
![Page 96: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/96.jpg)
User-reported errors are difficult to diagnose
![Page 97: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/97.jpg)
Wouldn’t it be useful to see the complete click-path?
![Page 98: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/98.jpg)
BUNYAN
Thin ruby layer around a MongoDB capped collection
http://github.com/ajsharp/bunyan
![Page 99: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/99.jpg)
BUNYAN
Still needs a middleware api.
Want to contribute?
http://github.com/ajsharp/bunyan
![Page 100: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/100.jpg)
Text
require 'bunyan'
Bunyan::Logger.configure do database 'my_bunyan_db' collection "#{Rails.env}_bunyan_log" size 1073741824 # 1.gigabyteend
![Page 101: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/101.jpg)
SINATRA FRONT-END TO BUNYAN
PAPERMILLhttp://github.com/ajsharp/papermill
![Page 102: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/102.jpg)
DEMO TIME
PAPERMILLhttp://github.com/ajsharp/papermill
![Page 103: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/103.jpg)
![Page 104: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/104.jpg)
BLOGGING APPLICATION
![Page 105: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/105.jpg)
BLOGGING APPLICATION
Much easier to model with Mongo than a relational database
![Page 106: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/106.jpg)
A post has an author
BLOGGING APPLICATION
![Page 107: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/107.jpg)
A post has an author
A post has many tags
BLOGGING APPLICATION
![Page 108: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/108.jpg)
A post has an author
A post has many tags
BLOGGING APPLICATION
A post has many comments
![Page 109: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/109.jpg)
A post has an author
A post has many tags
A post has many comments
Instead of joining separate tables,we can use embedded documents.
BLOGGING APPLICATION
![Page 110: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/110.jpg)
MONGOMAPPER
![Page 111: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/111.jpg)
MONGOMAPPER•MongoDB “ORM” developed by John Nunemaker
![Page 112: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/112.jpg)
MONGOMAPPER•MongoDB “ORM” developed by John Nunemaker
•Very similar syntax to DataMapper
![Page 113: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/113.jpg)
MONGOMAPPER•MongoDB “ORM” developed by John Nunemaker
•Very similar syntax to DataMapper
•Declarative rather than inheritance-based
![Page 114: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/114.jpg)
MONGOMAPPER•MongoDB “ORM” developed by John Nunemaker
•Very similar syntax to DataMapper
•Declarative rather than inheritance-based
•Very easy to drop into rails
![Page 115: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/115.jpg)
require 'mongo'connection = Mongo::Connection.new.db("blog_app")
class Post include MongoMapper::Document belongs_to :author, :class_name => "User" key :title, String, :required => true key :body, String, :required => true key :author_id, Integer, :required => true key :published_at, Time key :published, Boolean, :default => false key :tags, Array, :default => [] timestamps!end
MONGOMAPPER
![Page 116: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/116.jpg)
INDEXES!
Post.collection.create_index('tags')
Post.collection.create_index('title')
![Page 117: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/117.jpg)
WINS
![Page 118: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/118.jpg)
WINS
Simpler persistence model matches simple object model
![Page 119: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/119.jpg)
NEXT STEPS
![Page 120: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/120.jpg)
OBJECT-DOCUMENT MAPPERS
• Ruby mongo driver
• github.com/mongodb/mongo-ruby-driver
• MongoMapper
• github.com/jnunemaker/mongomapper
• Mongoid
• github.com/durran/mongoid
![Page 121: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/121.jpg)
MONGOMAPPER• DataMapper-like API
• good for moving from a sql schema to mongo
• easy to drop into rails
• works with rails 3
![Page 122: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/122.jpg)
MONGOID• DataMapper-like API
• uses ActiveModel, so familiar validation syntax
• more opinionated towards embedded docs
• easy to drop into rails
• rails 2 - mongoid 1.x
• rails 3 - mongoid 2.x
![Page 123: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/123.jpg)
mongodb.org
![Page 124: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/124.jpg)
MOST IMPORTANTLY
最も重要な...
![Page 125: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/125.jpg)
WE MUST ARRIVE AT THE WHISKEY BAR EARLIER
TOMORROW我々はウイスキーバーは明日、以前に到着する必要があります
![Page 126: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/126.jpg)
BECAUSE IT CLOSES AT MIDNIGHT
;-)
それは真夜中に閉じるため
![Page 127: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/127.jpg)
QUESTIONS?
![Page 128: Practical Ruby Projects with MongoDB - Ruby Kaigi 2010](https://reader038.fdocuments.net/reader038/viewer/2022102901/5555a8dcd8b42afe5d8b4658/html5/thumbnails/128.jpg)
THANKS!