Ordered ListJohn NunemakerMongoSF San Francisco, CA
April 30, 2010
MongoMapperMapping Ruby To and From Mongo
UsingExtendingProphesying
UsingExtendingProphesying
...and many more.
class Itemend
class Item include MongoMapper::Documentend
class Datum include MongoMapper::EmbeddedDocumentend
Free Stuff
Free StuffPersistence
Free StuffPersistence
Validations [presence, length, inclusion, ...]
Free StuffPersistence
Validations [presence, length, inclusion, ...]
Callbacks [before/after validate, create, save, ...]
Free StuffPersistence
Validations [presence, length, inclusion, ...]
Callbacks [before/after validate, create, save, ...]
Associations [many, belongs_to, one, ...]
Free StuffPersistence
Validations [presence, length, inclusion, ...]
Callbacks [before/after validate, create, save, ...]
Associations [many, belongs_to, one, ...]
Serialization [to_json]
PersistenceNever gonna give you up
item = Item.create({ :title => 'MongoSF', :location => 'San Fran', :when => Time.now})
puts item.to_mongo
{ "_id" => ObjectID('4bd8cc5cbcd1b313b3000001'), "title" => "MongoSF", "location" => "San Fran", "when" => Wed Apr 28 17:01:32 -0700 2010}
item = Item.newitem[:title] = 'MongoSF'item[:location] = 'San Fran'item[:when] = Time.nowitem.save
puts item.to_mongo
{ "_id" => ObjectID('4bd8cc5cbcd1b313b3000001'), "title" => "MongoSF", "location" => "San Fran", "when" => Wed Apr 28 17:01:32 -0700 2010}
TypesWhat you be baby boo?
class Item include MongoMapper::Document key :title, String key :path, Stringend
But Mongo is Schema-less?
Think App SchemaInstead of database schema
Built-in TypesArray, Binary, Boolean, Date, Float, Hash, Integer, Nil, ObjectId, Set, String, Time
Custom TypesIts shake and bake and I helped!
class Set def self.to_mongo(value) value.to_a end def self.from_mongo(value) Set.new(value || []) endend
class DowncasedString def self.to_mongo(value) value.nil? ? nil : value.to_s.downcase end def self.from_mongo(value) value.nil? ? nil : value.to_s.downcase endend
class User include MongoMapper::Document key :email, DowncasedStringend
TypelessI do not know who I am
class Foo include MongoMapper::Document key :barend
foo = Foo.new
foo.bar = 'Some text'# foo.bar => "Some text"
foo.bar = 24# foo.bar => 24
ValidationsCurrently using fork of validatable
class Item include MongoMapper::Document
key :title, String validates_presence_of :titleend
class Item include MongoMapper::Document
key :title, String, :required => trueend
validates_presence_of validates_length_ofvalidates_format_ofvalidates_numericality_ofvalidates_acceptance_ofvalidates_confirmation_ofvalidates_inclusion_of validates_exclusion_of
CallbacksRipped from AS2’s cold, dead fingers
class Item include MongoMapper::Document key :title, String key :path, String key :parent_id, ObjectId belongs_to :parent
before_validation :set_path
private def set_path self.path = parent.path + title.parameterize endend
:before_save, :after_save,:before_create, :after_create,:before_update, :after_update,:before_validation, :after_validation,:before_validation_on_create, :after_validation_on_create,:before_validation_on_update, :after_validation_on_update,:before_destroy, :after_destroy,:validate_on_create, :validate_on_update,:validate
AssociationsI belong to you
to Docsbelongs_to, one, many, many :in
class Account include MongoMapper::Document
many :sitesend
class Site include MongoMapper::Document
key :account_id, ObjectId belongs_to :accountend
account = Account.create(:title => 'OL', :sites => [ Site.new(:title => 'OL', :domain => 'orderedlist.com'), Site.new(:title => 'RT', :domain => 'railstips.org'),])
[ { '_id' => ObjectID('...'), 'title' => 'OL', 'domain' => 'orderedlist.com' 'account_id' => ObjectID('...'), }, { '_id' => ObjectID('...'), 'title' => 'RT', 'domain' => 'railstips.org' 'account_id' => ObjectID('...'), }]
to Embedded Docsmany, one
class Item include MongoMapper::Document
many :dataend
class Datum include MongoMapper::EmbeddedDocument
key :key, String key :valueend
Item.create(:title => 'MongoSF', :data => [ Datum.new(:key => 'description', :value => 'Awesome.')])
{ '_id' => ObjectID('...'), 'title' => 'MongoSF', 'data' => [ { '_id' => ObjectID('...'), 'key' => 'description' 'value' => 'Awesome.', } ]}
UsingExtendingProphesying
PluginsConventional way to extend
Powered by PluginsMongoMapper is
associations, callbacks, clone, descendants, dirty, equality, identity_map, inspect, keys, logger, modifiers, pagination, persistence, protected, rails, serialization, timestamps, userstamps, validations
module MongoMapper module Plugins def plugins @plugins ||= [] end
def plugin(mod) extend mod::ClassMethods if mod.const_defined?(:ClassMethods) include mod::InstanceMethods if mod.const_defined?(:InstanceMethods) mod.configure(self) if mod.respond_to?(:configure) plugins << mod end endend
module ActsAsListFu module ClassMethods def reorder(ids) # reorder ids... end end
module InstanceMethods def move_to_top # move to top end end
def self.configure(model) model.key :position, Integer, :default => 1 endend
class Foo include MongoMapper::Document plugin ActsAsListFuend
Foo.reorder(...)Foo.new.move_to_top
Good ExampleJoint: github.com/jnunemaker/joint
class Asset include MongoMapper::Document plugin Joint
attachment :image attachment :fileend
asset = Asset.create({ :image => File.open('john.jpg', 'r'), :file => File.open('foo.txt', 'r'),})
asset.image.idasset.image.nameasset.image.typeasset.image.sizeasset.image.read
Descendant AppendsFancy Schmancy and Stolen
module FancySchmancy def some_method puts 'some method' endend
MongoMapper::Document.append_extensions(FancySchmancy)
class Foo include MongoMapper::Documentend
Foo.some_method # puts 'some method'Foo.new.some_method # NoMethodError
module FancySchmancy def some_method puts 'some method' endend
MongoMapper::Document.append_inclusions(FancySchmancy)
class Foo include MongoMapper::Documentend
Foo.new.some_method # puts 'some method'Foo.some_method # NoMethodError
module FancySchmancy def some_method puts 'some method' endend
class Foo include MongoMapper::Documentend
MongoMapper::Document.append_extensions(FancySchmancy)
class Bar include MongoMapper::Documentend
Foo.some_method # puts 'some method'Bar.some_method # puts 'some method'
module IdentityMapAddition def self.included(model) model.plugin MongoMapper::Plugins::IdentityMap endend
MongoMapper::Document.append_inclusions(IdentityMapAddition)
UsingExtendingProphesying
Active ModelValidations, callbacks, serialization, etc.
Blank DocumentMix and match whatever you want
Mongo::QueryFancy query magic for the ruby drivergithub.com/jnunemaker/mongo-query
Ordered List
Thank [email protected]
John NunemakerMongoSF San Francisco, CAApril 30, 2010
@jnunemaker