Practical Ruby Projects With Mongo Db

84
Practical Ruby Projects with

Transcript of Practical Ruby Projects With Mongo Db

Page 1: Practical Ruby Projects With Mongo Db

Practical Ruby Projects with

Page 2: Practical Ruby Projects With Mongo Db

Who am I?

Alex Sharp

Amphibious Code Creature at OptimisDev

@ajsharp

alexjsharp.tumblr.com

Page 3: Practical Ruby Projects With Mongo Db

We’re going to talk about two things.

Page 4: Practical Ruby Projects With Mongo Db

1. Why/how MongoDB is practical

Page 5: Practical Ruby Projects With Mongo Db

2. A few examples of how to use MongoDB with Ruby

Page 6: Practical Ruby Projects With Mongo Db

So what’s all this “practical” talk?

Page 7: Practical Ruby Projects With Mongo Db

Imagine if databases were cars...

Page 8: Practical Ruby Projects With Mongo Db

Any takers for MySQL?

Page 9: Practical Ruby Projects With Mongo Db

RDBMS (i.e. mysql) =~

Page 10: Practical Ruby Projects With Mongo Db

In other words...

Page 11: Practical Ruby Projects With Mongo Db

MySQL is very reliable.

Page 12: Practical Ruby Projects With Mongo Db

But it may not be a speed demon.

Page 13: Practical Ruby Projects With Mongo Db

Guesses for MongoDB?

Page 14: Practical Ruby Projects With Mongo Db

MongoDB =~

Page 15: Practical Ruby Projects With Mongo Db

Mongo is reliable too, but they’re also go pretty damn

fast.

Page 16: Practical Ruby Projects With Mongo Db

The Practicality of MongoDB

Page 17: Practical Ruby Projects With Mongo Db

Objects weren’t made for SQL schemas

Simplifying schema design

Page 18: Practical Ruby Projects With Mongo Db

Objects weren’t meant to be “mapped” to a SQL schema

Simplifying schema design

Page 19: Practical Ruby Projects With Mongo Db

We’re forced to create “relationships” when what we really want is properties for our objects.

Simplifying schema design

Page 20: Practical Ruby Projects With Mongo Db

Non-relational databases are better suited for objects

Simplifying schema design

Page 21: Practical Ruby Projects With Mongo Db

Maps/hashes/associative arrays are arguably among the best object serialization formats

Simplifying schema design

Page 22: Practical Ruby Projects With Mongo Db

@alex = Person.new( :name => "alex", :friends => [Friend.new("Jim"), Friend.new("Bob")])

Page 23: Practical Ruby Projects With Mongo Db

<Person:0x10017d030 @name="alex", @friends= [#<Friend:0x10017d0a8 @name="Jim">, #<Friend:0x10017d058 @name="Bob">]>

Native ruby object

Page 24: Practical Ruby Projects With Mongo Db

@alex.to_json{ name: "alex", friends: [{ name: "Jim" }, { name: "Bob" }] }

JSON Representation

Page 25: Practical Ruby Projects With Mongo Db

SQL Schema Representation# in a SQL schemapeople: - name friends: - name - friend_id

Page 26: Practical Ruby Projects With Mongo Db

Ruby -> JSON -> SQL

people: - name friends: - name - friend_id

@alex.to_json{ name: "alex", friends: [{ name: "Jim" }, { name: "Bob" }] }

<Person:0x10017d030 @name="alex", @friends= [#<Friend:0x10017d0a8 @name="Jim">, #<Friend:0x10017d058 @name="Bob">]>

Ruby

JSON

SQL

Page 27: Practical Ruby Projects With Mongo Db

Ruby -> JSON -> SQL

people: - name friends: - name - friend_id

@alex.to_json{ name: "alex", friends: [{ name: "Jim" }, { name: "Bob" }] }

<Person:0x10017d030 @name="alex", @friends= [#<Friend:0x10017d0a8 @name="Jim">, #<Friend:0x10017d058 @name="Bob">]>

Ruby

JSON

SQLFeels like we’re having to work too hard here

Page 28: Practical Ruby Projects With Mongo Db

@alex.to_json{ name: "alex", friends: [{ name: "Jim" }, { name: "Bob" }] }

Mongo Representation

Page 29: Practical Ruby Projects With Mongo Db

@alex.to_json{ name: "alex", friends: [{ name: "Jim" }, { name: "Bob" }] }

Mongo Representation

In Mongo, friends is an “embedded document”

Page 30: Practical Ruby Projects With Mongo Db

@alex.to_json{ name: "alex", friends: [{ name: "Jim" }, { name: "Bob" }] }

Mongo Representation

Great for one-to-many associations

Page 31: Practical Ruby Projects With Mongo Db

@alex.to_json{ name: "alex", friends: [{ name: "Jim" }, { name: "Bob" }] }

Mongo Representation

No JOINS required.

Page 32: Practical Ruby Projects With Mongo Db

@alex.to_json{ name: "alex", friends: [{ name: "Jim" }, { name: "Bob" }] }

Mongo Representation

This is a good thing for scalability, because JOINS limit our ability to horizontally scale.

Page 33: Practical Ruby Projects With Mongo Db

@alex.to_json{ name: "alex", friends: [{ name: "Jim" }, { name: "Bob" }] }

Mongo Representation

But more importantly, this seems more intuitive than messing with foreign keys

Page 34: Practical Ruby Projects With Mongo Db

Ok, so what?

You’re probably thinking...

“Listen GUY, SQL isn’t that bad”

Page 35: Practical Ruby Projects With Mongo Db

Ok, so what?

True.

Page 36: Practical Ruby Projects With Mongo Db

Ok, so what?

SQL is actually really, really good at what it was designed to do.

Page 37: Practical Ruby Projects With Mongo Db

Ok, so what?

But SQL schemas are designed for storing and querying data, not necessarily modeling objects.

Page 38: Practical Ruby Projects With Mongo Db

Ok, so what?

It is called Structured Query Language.

Page 39: Practical Ruby Projects With Mongo Db

Ok, so what?

And to talk to these schemas in software, we use ORMs.

Page 40: Practical Ruby Projects With Mongo Db

Ok, so what?

ORM stands for Object Relational Mapper

Page 41: Practical Ruby Projects With Mongo Db

Ok, so what?

We need ORMs to bridge the gap between SQL and native objects (in our case, Ruby objects)

Page 42: Practical Ruby Projects With Mongo Db

Ok, so what?

I don’t want to map my objects to a schema designed for querying data.

Page 43: Practical Ruby Projects With Mongo Db

Ok, so what?

I want to store my objects in a datastore that was designed for storing objects

Page 44: Practical Ruby Projects With Mongo Db

Ok, so what?

Mongo is great for this b/c it stores objects (documents) as binary JSON

Page 45: Practical Ruby Projects With Mongo Db

Ok, so what?

And as we’ve seen, JSON is great for representing native objects

Page 46: Practical Ruby Projects With Mongo Db

Ok, so what?

This is important because when I’m writing an application, I don’t want to accomodate my objects to my datastore.

Page 47: Practical Ruby Projects With Mongo Db

Ok, so what?

I want something flexible that stays out of my way, but doesn’t sacrifice performance.

Page 48: Practical Ruby Projects With Mongo Db

Schema design for humans, not machines

i.e. document-oriented is awesome

schema-less is for adults

Pragmatic balance of performance and functionality

Speed/performance of mongo is super awesome

Scalability features are really powerful too

In a Nutshell

Page 49: Practical Ruby Projects With Mongo Db

Practical Projects

Page 50: Practical Ruby Projects With Mongo Db

Three Examples

1.Blogging Application

2.Accounting Application

3.Logging

Page 51: Practical Ruby Projects With Mongo Db

Blogging Application

Page 52: Practical Ruby Projects With Mongo Db

Blogging Application

Much easier to model with Mongo than a relational database

Page 53: Practical Ruby Projects With Mongo Db

Blogging Application

A post has an author

Page 54: Practical Ruby Projects With Mongo Db

Blogging Application

A post has an author

A post has many tags

Page 55: Practical Ruby Projects With Mongo Db

Blogging Application

A post has an author

A post has many tags

A post has many comments

Page 56: Practical Ruby Projects With Mongo Db

Blogging Application

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.

Page 57: Practical Ruby Projects With Mongo Db

require 'mongo'

conn = Mongo::Connection.new.db('bloggery')posts = conn.collection('posts')authors = conn.collection('authors')

Page 58: Practical Ruby Projects With Mongo Db

# returns a Mongo::ObjectID objectalex = authors.save :name => "Alex"post = posts.save( :title => 'Post title', :body => 'Massive potification...', :tags => ['laruby', 'omg', 'lolcats'], :comments => [ { :name => "Loudmouth McGee", :email => '[email protected]', :body => "Something really ranty..." } ], :author_id => alex)

Page 59: Practical Ruby Projects With Mongo Db

# returns a Mongo::ObjectID objectalex = authors.save :name => "Alex"post = posts.save( :title => 'Post title', :body => 'Massive potification...', :tags => ['laruby', 'omg', 'lolcats'], :comments => [ { :name => "Loudmouth McGee", :email => '[email protected]', :body => "Something really ranty..." } ], :author_id => alex)

Joins not necessary. Sweet.

Page 60: Practical Ruby Projects With Mongo Db

Logging with Capped Collections

Page 61: Practical Ruby Projects With Mongo Db

Fixed-sized, limited operation, auto age-out collections (kinda like memcached)

Fixed insertion order

Super fast (faster than normal writes)

Ideal for logging and caching

Capped collections

Page 62: Practical Ruby Projects With Mongo Db

This is awesome.

Page 63: Practical Ruby Projects With Mongo Db

Now we have logs we can query (and analyze)

Page 64: Practical Ruby Projects With Mongo Db

Can also be used for troubleshooting when things

go wrong

Page 65: Practical Ruby Projects With Mongo Db

Bunyan

Thin ruby layer around a Mongo capped collection

Page 66: Practical Ruby Projects With Mongo Db

Text

require 'bunyan'

Bunyan::Logger.configure do |c| c.database 'my_bunyan_db' c.collection 'development_log' # == 100.megabytes if using rails c.size 104857600 end

Bunyan::Logger.save( :request_method => 'get', :status_code => 200)

Page 67: Practical Ruby Projects With Mongo Db

A simple accounting application (maybe)

Page 68: Practical Ruby Projects With Mongo Db

The object model

ledger

transactions

entries

*

*

Page 69: Practical Ruby Projects With Mongo Db

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

{Transaction {

Transaction

Page 70: Practical Ruby Projects With Mongo Db

Object model summary

Each ledger transaction belongs to a ledger.

Each ledger transaction has two ledger entries which must balance.

Page 71: Practical Ruby Projects With Mongo Db

@credit_entry = LedgerEntry.new :account => "Cash", :amount => 100.00, :type => "credit"@debit_entry = LedgerEntry.new :account => "Notes Pay.", :amount => 100.00, :type => "debit"

@ledger_transaction = LedgerTransaction.new :ledger_id => 1, :ledger_entries => [@credit_entry, @debit_entry]

Object Model with ActiveRecord

Page 72: Practical Ruby Projects With Mongo Db

Object Model with Mongo@ledger_transaction = LedgerTransaction.new :ledger_id => 1, :ledger_entries => [ { :account => 'Cash', :type => "credit", :amount => 100.00 }, { :account => 'Notes Pay.', :type => "debit", :amount => 100.00 } ]

Page 73: Practical Ruby Projects With Mongo Db

Object Model with Mongo@ledger_transaction = LedgerTransaction.new :ledger_id => 1, :ledger_entries => [ { :account => 'Cash', :type => "credit", :amount => 100.00 }, { :account => 'Notes Pay.', :type => "debit", :amount => 100.00 } ]

This is the perfect case for embedded documents.

Page 74: Practical Ruby Projects With Mongo Db

Object Model with Mongo@ledger_transaction = LedgerTransaction.new :ledger_id => 1, :ledger_entries => [ { :account => 'Cash', :type => "credit", :amount => 100.00 }, { :account => 'Notes Pay.', :type => "debit", :amount => 100.00 } ]

We would never have a ledger entry w/o a transaction.

Page 75: Practical Ruby Projects With Mongo Db

Using mongo w/ Ruby

Ruby mongo driver

MongoMapper

MongoID

Many other ORM/ODM’s under active development

Page 76: Practical Ruby Projects With Mongo Db

MongoMapper

Page 77: Practical Ruby Projects With Mongo Db

MongoMapper

• MongoDB “ORM” developed by John Nunemaker

Page 78: Practical Ruby Projects With Mongo Db

MongoMapper

• MongoDB “ORM” developed by John Nunemaker

• author of HttpParty

Page 79: Practical Ruby Projects With Mongo Db

MongoMapper

• MongoDB “ORM” developed by John Nunemaker

• author of HttpParty

• Very similar syntax to DataMapper

Page 80: Practical Ruby Projects With Mongo Db

MongoMapper

• MongoDB “ORM” developed by John Nunemaker

• author of HttpParty

• Very similar syntax to DataMapper

• Declarative rather than inheritance-based

Page 81: Practical Ruby Projects With Mongo Db

MongoMapper

• MongoDB “ORM” developed by John Nunemaker

• author of HttpParty

• Very similar syntax to DataMapper

• Declarative rather than inheritance-based

• Very easy to drop into rails

Page 82: Practical Ruby Projects With Mongo Db

class Post include MongoMapper::Document

belongs_to :author, :class_name => "User"

key :title, String, :required => true key :body, String key :author_id, Integer, :required => true key :published_at, Time key :published, Boolean, :default => false timestamps!

many :tagsend

MongoMapper

class Tag include MongoMapper::EmbeddedDocument

key :name, String, :required => trueend

Page 83: Practical Ruby Projects With Mongo Db

Questions?

Page 84: Practical Ruby Projects With Mongo Db

Thanks!