The Ruby/mongoDB ecosystem

4,231 views

Published on

Published in: Technology
0 Comments
6 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
4,231
On SlideShare
0
From Embeds
0
Number of Embeds
18
Actions
Shares
0
Downloads
0
Comments
0
Likes
6
Embeds 0
No embeds

No notes for slide










































  • The Ruby/mongoDB ecosystem

    1. 1. The Ruby / MongoDB ecosystem Harold Giménez Mongo Boston - Sept 20, 2010
    2. 2. Harold Giménez @hgimenez thoughtbot, inc.
    3. 3. Why Ruby? • Expressiveness, Elegance • Powerful • Simple, flexible syntax • Open Source • Community • Library support: rubygems
    4. 4. ...maybe too many libraries
    5. 5. mongo-ruby-driver http://github.com/mongodb/mongo-ruby-driver
    6. 6. Start here Closest to mongo’s lingo, almost-native query syntax require 'mongo' db = Mongo::Connection.new.db('mongo-boston') people = db.collection('people') people.insert({'name' => 'Harold', 'address' => { 'city' => 'Boston' } }) people.insert({'name' => 'Jack'}) people.find('name' => 'Harold').to_a people.find('address.city' => 'Boston').to_a
    7. 7. Tools mongoid Mongomatic MongoMapper MongoODM connection, cursor, CRUD mongo-ruby-driver
    8. 8. mongoid http://github.com/mongoid/mongoid
    9. 9. class Person include Mongoid::Document field :cool_dude, :type => Boolean, :default => false field :name field :age, :type => Integer embeds_one :address validates_presence_of :name end class Address include Mongoid::Document field :city field :zip_code embedded_in :person, :inverse_of => :address end
    10. 10. class Person include Mongoid::Document field :cool_dude, :type => Boolean, :default => false field :name field :age, :type => Integer embeds_one :address embeds_many references_one validates_presence_of :name references_many end referenced_in class Address include Mongoid::Document field :city field :zip_code embedded_in :person, :inverse_of => :address end
    11. 11. > me = Person.create!(:cool_dude => true) Mongoid::Errors::Validations: Validation failed - Name can't be blank. > me = Person.create(:name => 'Harold', :cool_dude => true) => #<Person name: "Harold", _id: BSON::ObjectId('4c950d73fff2cb4262000007'), cool_dude: true> > me.address = Address.new(:city => 'Boston') => #<Address city: "Boston", zip_code: nil, _id: BSON::ObjectId('4c950d83fff2cb4262000008')> > me.save { "_id" : ObjectId("4c950d73fff2cb4262000007"), "address" : { "_id" : ObjectId("4c950d83fff2cb4262000008"), "city" : "Boston", "zip_code" : null }, "name" : "Harold", "cool_dude" : true }
    12. 12. mongoid criteria me = Person.create(:name => 'Harold', :cool_dude => true) another_harold = Person.create(:name => 'Harold') someone_else = Person.create(:name => 'Jack', :cool_dude => true) Person.where(:name => 'Harold') Person.where(:cool_dude => true) Person.where(:name => 'Harold').where(:cool_dude => true) class Person def self.cool_dudes where(:cool_dude => true) end def self.harolds where(:name => 'Harold') end end Person.cool_dudes.harolds Person.harolds.not_in("address.city" => ["Boston"]).asc("address.city")Person.cool_dudes.only(:id).where("address. city" => "Boston")
    13. 13. more querying Person.all_in(:name => [ "Harold", "Ha, Lord!" ]) Person.any_in(:status => ["Single", "Divorced", "Separated"]) Person.any_of({ :name => "Harold" }, { :cool_dude => true }) Person.and(:name => "Harold", :cool_dude => false) Person.excludes("address.city" => "Boston") Person.limit(20) Person.not_in(:name => ["Harold", "Jack"]) Person.where(:address.exists => true) Person.where(:age.gt => 21) Person.where(:age.gte => 21) Person.where(:age.lt => 30) Person.where(:age.lte => 30)
    14. 14. Mongoid::Paranoia class Person include Mongoid::Document include Mongoid::Paranoia end person.delete # person.deleted_at = Time.now person.restore # phew! person.delete! person.restore # it's gone :(
    15. 15. cursor proxy module Mongoid class Cursor include Enumerable OPERATIONS = [ :close, :closed?, :count, :explain, :fields, :full_collection_name, :hint, :limit, :order, :query_options_hash, :query_opts, :selector, :skip, :snapshot, :sort, :timeout ] OPERATIONS.each do |name| define_method(name) { |*args| @cursor.send(name, *args) } end def each # ... end def next_document # ... end def to_a # ... end end
    16. 16. Enables caching vs. lazy loading of big datasets Person.all.cache.each { |person| person.hug } or class Person include Mongoid::Document cache end Person.all.each { |person| person.hug }
    17. 17. ActiveModel under the hood ActiveModel::Conversion ActiveModel::Naming ActiveModel::Serialization ActiveModel::MassAssignmentSecurity ActiveModel::Translation ActiveModel::Validation ActiveModel::Callbacks
    18. 18. MongoMapper http://github.com/jnunemaker/mongomapper
    19. 19. class Person include MongoMapper::Document key :cool_dude, Boolean, :default => false key :name, String, :required => true key :age, Integer one :address end class Address include MongoMapper::EmbeddedDocument key :city, String key :zip_code, String end
    20. 20. class Person include MongoMapper::Document key :cool_dude, Boolean, :default => false key :name, String, :required => true key :age, Integer one :address many end belongs_to class Address include MongoMapper::EmbeddedDocument key :city, String key :zip_code, String end
    21. 21. class Person include MongoMapper::Document key :cool_dude, Boolean, :default => false key :name, String, :required => true key :age, Integer one :address end class Address include MongoMapper::EmbeddedDocument key :city, String key :zip_code, String end
    22. 22. class Person include MongoMapper::Document key :cool_dude, Boolean, :default => false key :name, String, :required => true key :age, Integer one :address Alternative end validation syntax class Address include MongoMapper::EmbeddedDocument key :city, String key :zip_code, String end
    23. 23. > me = Person.create!(:cool_dude => true) MongoMapper::DocumentNotValid: Validation failed: Name can't be empty > me = Person.create(:name => 'Harold', :cool_dude => true) => #<Person name: "Harold", _id: BSON::ObjectId('4c9508fbfff2cb4096000007'), cool_dude: true> > me.address = Address.new(:city => 'Boston') => #<Address city: "Boston", zip_code: nil, _id: BSON::ObjectId('4c950911fff2cb4096000008')> > me.save { "_id" : ObjectId("4c9508fbfff2cb4096000007"), "address" : { "_id" : ObjectId("4c950911fff2cb4096000008"), "city" : "Boston", "zip_code" : null }, "name" : "Harold", "cool_dude" : true }
    24. 24. Plugin architecture 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 end end associations, dirty, document dynamic_querying, embedded_document, equality indexes, logger modifiers, pagination persistence, protected, querying safe, SCI, scopes, serialization, validations, and more (pretty much everything in MM)
    25. 25. Querying (plucky) Person.where(:address.exists => true).all Person.where(:age.gt => 21).limit(10).all Person.where(:age.gte => 21).all Person.where(:age.lt => 30).all Person.where(:age.lte => 30).all ( Similar to mongoid’s querying and scoping ) Except for no support for #not_in, #exists, #any_of and others found in mongoid
    26. 26. Notable difference: mongoid MongoMapper #<Mongoid::Criteria: Person.where(:name => 'Harold') 0x101754bd8 @klass=Person, #<Plucky::Query name: @options={}, @documents=[], "Harold"> @selector={:name=>"Harold"}> #<Mongoid::Criteria: 0x101754bd8 @klass=Person, Person.where(:name => 'Harold').all @options={}, @documents=[], [#<Person name: "Harold"] @selector={:name=>"Harold"}> Person.where(:name => 'Harold').all.to_a [#<Person name: "Harold"] [#<Person name: "Harold"] or #each, #map, etc
    27. 27. cache_key class Person include MongoMapper::Document end Person.new.cache_key # => "Person/new" Person.create.cache_key # => "Person/4c9508fbfff2cb4096000007"
    28. 28. Custom data types class MongoSet def self.to_mongo(value) value.to_a end def self.from_mongo(value) Set.new(value || []) end end class Person include MongoMapper::Document key :aliases, MongoSet end
    29. 29. Typecasting class Person include MongoMapper::Document key :friend_ids, Array, :typecast => 'ObjectId' end Person.new(:friend_ids => %w(4c950520fff2cb3fb9000004 4c950558fff2cb3fb9000005 4c950911fff2cb4096000008) )
    30. 30. Both MongoMapper and Mongoid provide: #cache_key Cursor wrapper/cache plugins embraces ActiveModel custom data types thorough query syntax abstraction typecasting Persistance Querying Associations Embedded Docs Serialization Dynamic Finders Pagination Scopes Rails 3
    31. 31. Rails 2, you are... ing oy t nn no , a ’s ly at g h re u e in t yw he .th us an .. o c ing go e! MongoMapper m d to .d ea .. Mongoid
    32. 32. MongoODM http://github.com/carlosparamio/mongo_odm Mongomatic MongoMapper http://github.com/benmyles/mongomatic
    33. 33. A fresh look Query chaining Lazy loading Validations Callbacks Rails integration Worth keeping an eye on!
    34. 34. Mongoid MongoMapper Side by side! Mongomatic MongoODM
    35. 35. Number of Files 300 250 200 project mongoid files MongoMapper mongomatic 150 MongoODM 100 50 May−09 Aug−09 Nov−09 Feb−10 May−10 Aug−10 day
    36. 36. Number of Lines 30000 number_of_lines project mongoid 20000 MongoMapper mongomatic MongoODM 10000 0 May−09 Aug−09 Nov−09 Feb−10 May−10 Aug−10 day
    37. 37. Number of Collaborators 80 60 project collaborators mongoid MongoMapper mongomatic 40 MongoODM 20 0 May−09 Aug−09 Nov−09 Feb−10 May−10 Aug−10 day
    38. 38. Number of Commits 1500 project 1000 mongoid commits MongoMapper mongomatic MongoODM 500 0 May−09 Aug−09 Nov−09 Feb−10 May−10 Aug−10 day
    39. 39. mongoid release cycle 25 20 prior_days 15 10 5 0 2.0.0.beta.102.0.0.beta1v0.0.1 v0.10.5v0.11.4v0.12.0 v0.2.5v0.3.2v0.4.2v0.4.8v0.5.2v0.5.7 v0.6.2v0.6.7 v0.7.2v0.7.7 v0.8.2v0.8.7 v0.9.11 v0.9.6v1.0.1v1.0.6v1.1.4 v1.2.13 v1.2.5v1.9.0 2.0.0.beta.11 2.0.0.beta11v0.10.2v0.11.1v0.11.7 v0.2.2v0.2.7v0.3.4v0.4.4v0.5.1v0.5.4v0.5.9v0.6.3v0.6.8 v0.7.3v0.7.8 v0.8.3v0.8.8 v0.9.12 v0.9.7v1.0.2v1.1.0v1.2.0 v1.2.14 v1.2.6v1.9.1 2.0.0.beta.12 2.0.0.beta2 v0.10.3v0.11.2v0.11.8 v0.2.3v0.3.0v0.4.0v0.4.5 v0.5.11 v0.5.8 v0.6.4v0.6.9 v0.7.4v0.7.9 v0.8.4v0.8.9 v0.9.2 v0.9.8v1.0.3v1.1.1v1.2.1 v1.2.15 v1.2.7v2.0.0 2.0.0.beta.13 2.0.0.beta7 v0.10.4v0.11.3v0.11.9 v0.2.4v0.3.1v0.4.1v0.4.7 v0.5.3 v0.6.0 v0.6.5v0.7.0 v0.7.5v0.8.0 v0.8.5v0.9.0 v0.9.3 v0.9.9v1.0.4v1.1.2 v1.2.11 v1.2.3v1.2.8 2.0.0.beta.14 2.0.0.beta8 v0.10.6v0.11.5 v0.2.0 v0.2.6v0.3.3v0.4.3v0.5.0 v0.5.5 v0.6.1 v0.6.6v0.7.1 v0.7.6v0.8.1 v0.8.6v0.9.1 v0.9.4 v1.0.0v1.0.5v1.1.3 v1.2.12 v1.2.4v1.2.9 2.0.0.beta.16 2.0.0.beta9 v0.11.0v0.11.6 v0.2.1 2.0.0.beta.17 2.0.0.beta.7 2.0.0.beta.8 v0.10.0 2.0.0.beta.9 v0.10.1 2.0.0.beta10 v0.5.10 v0.5.6 v0.6.10 v0.7.10 v0.8.10 v0.9.10 v0.9.5 v1.2.10 v1.2.2 v2.0.0.beta1 v2.0.0.beta3 v2.0.0.beta4 tag
    40. 40. MongoMapper release cycle 50 40 30 prior_days 20 10 0 v0.1.0 v0.1.2 v0.3.0 v0.3.2 v0.3.4 v0.4.0 v0.4.2 v0.5.1 v0.5.3 v0.5.5 v0.5.7 v0.6.0 v0.6.10 v0.6.3 v0.6.5 v0.6.7 v0.6.9 v0.7.1 v0.7.3 v0.7.5 v0.8.0 v0.8.2 v0.8.4 v0.1.1 v0.2.0 v0.3.1 v0.3.3 v0.3.5 v0.4.1 v0.5.0 v0.5.2 v0.5.4 v0.5.6 v0.5.8 v0.6.1 v0.6.2 v0.6.4 v0.6.6 v0.6.8 v0.7.0 v0.7.2 v0.7.4 v0.7.6 v0.8.1 v0.8.3 tag
    41. 41. the end

    ×