29
Schema-less Design An introduction to the Mongoid ODM

Using Mongoid with Ruby on Rails

Embed Size (px)

Citation preview

Page 1: Using Mongoid with Ruby on Rails

Schema-less Design An introduction to the Mongoid ODM

Page 2: Using Mongoid with Ruby on Rails

1. MongoDB

2. Mongoid ODM compares to ORM/SQL

3. Modelling Bitmaker Rainforest app without ActiveRecord

4. Going further

5. Conclusion

Overview

Page 3: Using Mongoid with Ruby on Rails

Questions going in• What is MongoDB?

• How does it compare from SQL-based databases?

• What does schema-less entail?

• How does ODM compare with ORM? Rainforest tutorial

• Worth it?

Page 4: Using Mongoid with Ruby on Rails

Object Document Mapper (ODM)

Translate between objects in code and document representation of data.

Object Relational Mapping translates between objects in code the the relational representation of the data.

Page 5: Using Mongoid with Ruby on Rails

MongoDB• Open-source database

• NoSQL (cluster friendly, 21st-century web, non-relational, schema-less)

• Data is stored in collections and documents whereas in SQL data is stored in tables and rows

• JSON-like structure to documents

Page 6: Using Mongoid with Ruby on Rails

Differs from SQL

No JOINS -> run two or more queries

Embed and Referencing of document/data objects

Fast querying

PostgreSQL has strict schema / MongoDB has implicit schema

Page 7: Using Mongoid with Ruby on Rails

Use cases

“Big Data” - large and unwieldy

90% of business data is unstructured

Increasing volume, variety and velocity

craigslist, Forbes, New York Times, Foursquare, etc.

Page 8: Using Mongoid with Ruby on Rails

The SetupInstall mongodb

https://docs.mongodb.org/manual/installation/

Run mongo server and mongo database in separate terminal tabs

Page 9: Using Mongoid with Ruby on Rails

~>rails new rainforest —skip-active-record

The Setup

Removes ActiveRecord from the application No schema.rb No migrations folder

gem 'mongoid', '~> 5.1'

~>bundle install

~>rails generate mongoid:configcreates config/mongoid.yml

Page 10: Using Mongoid with Ruby on Rails

application.rb

require File.expand_path('../boot', __FILE__)

require "rails" # Pick the frameworks you want: require "active_model/railtie" require "active_job/railtie" # require "active_record/railtie" require "action_controller/railtie" require "action_mailer/railtie" require "action_view/railtie" require "sprockets/railtie" require "rails/test_unit/railtie"

. . .

Page 11: Using Mongoid with Ruby on Rails

mongoid.yml

development: # Configure available database clients. (required) clients: # Defines the default client. (required) default: # Defines the name of the default database that Mongoid can connect to. # (required). database: rainforest_development # Provides the hosts the default client can connect to. Must be an array # of host:port pairs. (required) hosts: - localhost:27017 options: # Change the default write concern. (default = { w: 1 }) # write: # w: 1

Page 12: Using Mongoid with Ruby on Rails

Rainforest Appclass Product include Mongoid::Document field :name, type: String field :description, type: String field :price_in_cents, type: Integer . . .

embeds_many :reviews embeds_one :category end

class Category include Mongoid::Document field :name, type: String

embedded_in :product end

Page 13: Using Mongoid with Ruby on Rails

Product Controller

class ProductsController < ApplicationController . . . def product_params params.require(:product).permit(:name, :description, :price_in_cents, {category: [:category_id, :name]}) end end

Page 14: Using Mongoid with Ruby on Rails

Rainforest Appclass User include Mongoid::Document field :name, type: String field :email, type: String field :password, type: String . . . has_many :products

end

class Review include Mongoid::Document field :comment, type: String

field :user_id, type: BSON::ObjectId . . . embedded_in :product end

Page 15: Using Mongoid with Ruby on Rails

RelationsMongoid ODM associations similar to ActiveRecord ORM

Association is not just for Relational Mappers

Embeds One, Embeds Many, Has One, Has Many, Has And Belongs To Many, counter_cache (cache the counts of an associated model)

No has_many :through

Page 16: Using Mongoid with Ruby on Rails

BSON Objects

BSON: supports embedding of objects within arrays

Allow for extensions not part of JSON spec

Minimum overhead

Traverse quickly (fast to encode and decode)

Page 17: Using Mongoid with Ruby on Rails

{"_id" : ObjectId("5728b57b370d93124e000000"),"name" : "Day planner","description" : "Schedule events","price_in_cents" : 1299,"user_id" : ObjectId("5727b3b0370d93009d000000"),"category" : {

"_id" : ObjectId("5728b57b370d93124e000001"),"name" : “Office material"

},"reviews" : [

{"_id" : ObjectId("5728b5a3370d93124e000002"),"comment" : "A great product","user_id" : ObjectId("5727b3b0370d93009d000000")

}

Page 18: Using Mongoid with Ruby on Rails

[1] pry(main)> Product.first#<Product:0x007fc1290cd108> { :_id => BSON::ObjectId('56b54bc3370d93d2d5411757'), :category => { "_id" => BSON::ObjectId('570c78f1370d936468000000'), "name" => "Electronics" }, :description => "Listen to music without all the hassle of a cord.", :name => "Wireless Headphones", :price_in_cents => 60, :reviews => [ [0] { "_id" => BSON::ObjectId('56b54e59370d93d3b4fe9848'), "comment" => "Test comment”,

"user_id" => BSON::ObjectId('56eb9d92370d937950d21463 }, [1] { "_id" => BSON::ObjectId('56b54e5f370d93d3b4fe9849'), "comment" => "Checking comment\r\n”, "user_id" => BSON::ObjectId('56eb9d92370d937950d21463 }, [2] { "_id" => BSON::ObjectId('56b54e6d370d93d3b4fe984a'), "comment" => "Just bought these headphones.”, "user_id" => BSON::ObjectId('56eb9d92370d937950d21463 }, [0] { "_id" => BSON::ObjectId('5706dc66370d934ccd000000'), "comment" => "Checking embedded review", "user_id" => BSON::ObjectId('56eb9d92370d937950d21463') } ]}

Page 19: Using Mongoid with Ruby on Rails

Rails Console[3] pry(main)> products = Product.all#<Mongoid::Criteria selector: {} options: {} class: Product embedded: false>

The query doesn’t run until the data is requested

Page 20: Using Mongoid with Ruby on Rails

[6] pry(main)> products.each {|product|puts product.name }Wireless HeadphonesChromecast for TVFerrariATMComputerFerrari2Game BoySony HeadphonesSpeakersCarDell ComputerSamsung TelevisionAudi ConvertibleSnowmobile#<Mongoid::Contextual::Mongo:0x007fc129167550 @cache=nil, @klass=Product, @criteria=#<Mongoid::Criteria selector: {} options: {} class: Product embedded: false>, @collection=#<Mongo::Collection:0x70233797373000 namespace=rainforest_development.products>, @view=#<Mongo::Collection::View:0x70233797372780 namespace='rainforest_development.products @selector={} @options={}>, @cache_loaded=true>

Page 21: Using Mongoid with Ruby on Rails

Implicit schema

[9] pry(main)> product[:model] = "TS2-3Q78"

[8] pry(main)> product = Product.first

Page 22: Using Mongoid with Ruby on Rails

[1] pry(main)> Product.first#<Product:0x007fc1290cd108> { :_id => BSON::ObjectId('56b54bc3370d93d2d5411757'), :category => { "_id" => BSON::ObjectId('570c78f1370d936468000000'), "name" => "Electronics" }, :description => "Listen to music without all the hassle of a cord.", :model => "TS2-3Q78", :name => "Wireless Headphones", :price_in_cents => 60, :reviews => [ [0] { "_id" => BSON::ObjectId('56b54e59370d93d3b4fe9848'), "comment" => "Test comment" }, [1] { "_id" => BSON::ObjectId('56b54e5f370d93d3b4fe9849'), "comment" => "Checking comment\r\n" }, [2] { "_id" => BSON::ObjectId('56b54e6d370d93d3b4fe984a'), "comment" => "Just bought these headphones." }, [3] { "_id" => BSON::ObjectId('5706dc66370d934ccd000000'), "comment" => "Checking embedded review", "user_id" => BSON::ObjectId('56eb9d92370d937950d21463') } ]}

Page 23: Using Mongoid with Ruby on Rails

Mongoid

Similar syntax to ActiveRecord - associations, datatypes, etc.

No need for migrations

Great documentation; active community

Popular gems have mongoid counterpart (Devise, carrierwave-mongoid, mongoid-paperclip, geocoder, mongoid-rspec)

Setup is fast and mistakes quickly fixed (no rollbacks)

Page 24: Using Mongoid with Ruby on Rails

class Product include Mongoid::Document include Mongoid::Paperclip . . .

has_mongoid_attached_file :avatar, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: lambda { |image| ActionController::Base.helpers.asset_path('missing.png') }

validates_attachment_content_type :avatar,:content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]

end

class ProductsController < ApplicationController . . . def product_params params.require(:product).permit(:name, :description, :price_in_cents, :avatar, {category: [:category_id, :name]}) end

Page 25: Using Mongoid with Ruby on Rails

#<Product:0x007fc12b0db148> { :_id => BSON::ObjectId('570c32f9370d935b78000000'), :avatar_content_type => "image/jpeg", :avatar_file_name => "snowmobile.jpeg", :avatar_file_size => 7081, :avatar_fingerprint => "33234414813b3e3bf8a26281a2d7316f", :avatar_updated_at => 2016-04-12 00:56:31 UTC, :category => { "_id" => BSON::ObjectId('570c32f9370d935b78000001'), "name" => "Automobile" }, :description => "For northern living", :name => "Snowmobile", :price_in_cents => 345436 }

Page 26: Using Mongoid with Ruby on Rails

Going further• Indexing

• Map/Reduce to condense large volumes of data; work around for JOINS - rearrange data into aggregate forms

• Sharding

• Track data versioning

• GeoSpatial indexing

Page 27: Using Mongoid with Ruby on Rails

Worth it?• It depends what you want

• Have MongoDB serve up user info or cache preferences, integrate with social networks; SQL to handle payments/ordering

• Great for searching large amounts of data.

• PostgreSQL JSON type - support for arbitrary attributes (WARNING: anti-pattern)

• For this application, mongoid can work and clarified features for me, but SQL and Schema-based design seem optimized for this case

• Different ways to organize data and design models

• Learned some new things about ActiveRecord and PostgreSQL

Page 28: Using Mongoid with Ruby on Rails

Sourceshttps://www.mongodb.com/nosql-explained

Rege, Gautam. Ruby and MongoDB Web Development Beginner’s Guide, Packt Publishing, 2012

http://www.sarahmei.com/blog/2013/11/11/why-you-should-never-use-mongodb/ comment-page-1/

https://www.mongodb.com/compare/mongodb-mysql

https://github.com/meskyanichi/mongoid-paperclip

https://gorails.com/guides/setting-up-rails-4-with-mongodb-and-mongoid

https://gorails.com/blog/rails-4-0-with-mongodb-and-mongoid

http://stackoverflow.com/questions/26182890/perform-atomic-block-transactions-in-rails-with-mongoid

http://blog.2ndquadrant.com/postgresql-anti-patterns-unnecessary-jsonhstore-dynamic-columns/

Page 29: Using Mongoid with Ruby on Rails

@MrNickAltobelli [email protected] github: DataNick

www.nickaltobelli.com

Thank You!