Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Ror lab. season 2    - the 10th round -   Active RecordQuery Interface (1)     November 17th, 2012       Hyoseong Choi
ActiveRecord• No more SQL statements      MySQL                              PostgreSQL  : select * from tables      SQLit...
Finder Methods of  ActiveRecord1.where2.select3.group4.order5.reorder6.reverse_order7.limit8.offset9.joins10.includes11.lo...
Retrieving    A Single Object• find :ActiveRecord::RecordNotFound• first :nil• last :nil• first! : ActiveRecord::RecordNotFou...
Retrieving    A Single Object                            - find -  # Find the client with primary key (id) 10.  client = Cl...
Retrieving    A Single Object                            - first -  client = Client.first  # => #<Client id: 1, first_name: "...
Retrieving    A Single Object                             - last -  client = Client.last  # => #<Client id: 221, first_name...
Retrieving    A Single Object                          - first! -  client = Client.first!  # => #<Client id: 1, first_name: "...
Retrieving    A Single Object                           - last! -  client = Client.last!  # => #<Client id: 221, first_name...
Retrieving  Multiple Objects• Using multiple primary keys• In batches • find_each :batch_size, :start, • find_in_batches :ba...
Retrieving  Multiple Objects          - Using multiple primary keys -  # Find the clients with primary keys 1 and 10.  cli...
Retrieving       Multiple Objects                            - in Batches -                  to iterate over a large set o...
RetrievingMultiple Objects             - in Batches : find_each -User.find_each do |user|  NewsLetter.weekly_deliver(user)en...
Retrieving   Multiple Objects                - in Batches : find_each -  Article.find_each { |a| ... } # => iterate over all...
Retrieving     Multiple Objects              - in Batches : find_in_batches -    # Give add_invoices an array of 1000 invoi...
Retrieving   Multiple Objects              - in Batches : find_in_batches -Article.find_in_batches { |articles| articles.eac...
Conditions               - where -• String conditions• Array conditions• Hash conditions
String Conditions Client.where("orders_count = ‘2’")
Array ConditionsClient.where("orders_count = ?", params[:orders])Client.where("orders_count = ? AND locked = ?",        pa...
Array ConditionsClient.where("orders_count = ?", params[:orders])Client.where("orders_count = ? AND locked = ?",        pa...
Array Conditions - Placeholder conditions using symbols -Client.where("created_at >= :start_date AND created_at<= :end_dat...
Array Conditions                 - Range conditions -  Client.where(:created_at => (params[:start_date].to_date)..  (param...
Hash Conditions              - Equality conditions -Client.where(:locked => true)
Hash Conditions                 - Range conditions -  Client.where(:created_at => (Time.now.midnight -  1.day)..Time.now.m...
Hash Conditions                  - Subset conditions -  Client.where(:orders_count => [1,3,5])SELECT * FROM clients WHERE ...
OrderingClient.order("created_at")Client.order("created_at DESC")# ORClient.order("created_at ASC")
Selecting                                                                         ?If the select method is used, all the r...
Limit & OffsetClient.limit(5)   SELECT * FROM clients LIMIT 5Client.limit(5).offset(30)   SELECT * FROM clients LIMIT 5 OF...
Group  Order.select(  "date(created_at) as ordered_date, sum(price) as total_price")  .group("date(created_at)")SQL  SELEC...
Having  Order.select(  "date(created_at) as ordered_date, sum(price) as total_price")  .group("date(created_at)")  .having...
Overriding       Conditions• except• only• reorder• reverse_order
Overriding                  Conditions                                 - except -Post.where(id > 10).limit(20).order(id as...
Overriding                       Conditions                                        - only -Post.where(id > 10).limit(20).o...
Overriding          Conditions                      - reorder -class Post < ActiveRecord::Base  ..  ..  has_many :comments...
Overriding                 Conditions                          - reverse_order -  Client.where("orders_count > 10").order(...
Readonly Objectsclient = Client.readonly.firstclient.visits += 1client.save     ActiveRecord::ReadOnlyRecord exception
Locking Records    for Update• To prevent “race conditions”• To ensure “atomic updates”• Two locking mechanisms  ‣ Optimis...
Optimistic Locking• “lock_version” in DB table (default to 0)• set_locking_column to change column name  c1 = Client.find(1...
Optimistic Locking• To turn off,  ActiveRecord::Base.lock_optimistically = false• To override the name of the lock_version...
Pessimistic Locking• A locking mechanism by DB• An exclusive lock on the selected rows• Usually wrapped inside a transacti...
Pessimistic Locking  Item.transaction do    i = Item.lock.first    i.name = Jones    i.save SQL (0.2ms)   BEGIN Item Load (...
Pessimistic Locking Item.transaction do   i = Item.lock("LOCK IN SHARE MODE").find(1)   i.increment!(:views) end item = Ite...
Joining Tables        - Using a String SQL Fragment - Client.joins(LEFT OUTER JOIN addresses ON addresses.client_idSELECT ...
Joining Tables- Using Array/Hash of Named Associations -              only with INNER JOIN• a Single Association• Multiple...
Joining Tables           - Using Array/Hash of Named Associations -                                        only with INNER...
Joining Tables           - Using Array/Hash of Named Associations -                                        only with INNER...
Joining Tables           - Using Array/Hash of Named Associations -                                        only with INNER...
Joining Tables           - Using Array/Hash of Named Associations -                                        only with INNER...
Joining Tables  - Specifying Conditions on the Joined Tables -: using Array and String Conditions time_range = (Time.now.m...
감사합니다.
Upcoming SlideShare
Loading in …5
×

Active Record Query Interface (1), Season 2

This

  • Be the first to comment

Active Record Query Interface (1), Season 2

  1. 1. Ror lab. season 2 - the 10th round - Active RecordQuery Interface (1) November 17th, 2012 Hyoseong Choi
  2. 2. ActiveRecord• No more SQL statements MySQL PostgreSQL : select * from tables SQLite ... ORMAction Sequences Active 1. SQL query Record 2. Result set Finder 3. Ruby object Methods 4. (after_find callback)
  3. 3. Finder Methods of ActiveRecord1.where2.select3.group4.order5.reorder6.reverse_order7.limit8.offset9.joins10.includes11.lock12.readonly13.from14.having ActiveRecord::Relation
  4. 4. Retrieving A Single Object• find :ActiveRecord::RecordNotFound• first :nil• last :nil• first! : ActiveRecord::RecordNotFound• last! : ActiveRecord::RecordNotFound
  5. 5. Retrieving A Single Object - find - # Find the client with primary key (id) 10. client = Client.find(10)SELECT * FROM clients WHERE (clients.id = 10)ActiveRecord::RecordNotFound exception
  6. 6. Retrieving A Single Object - first - client = Client.first # => #<Client id: 1, first_name: "Lifo">SELECT * FROM clients LIMIT 1nil if no matching record is found
  7. 7. Retrieving A Single Object - last - client = Client.last # => #<Client id: 221, first_name: "Russel">SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1nil if no matching record is found
  8. 8. Retrieving A Single Object - first! - client = Client.first! # => #<Client id: 1, first_name: "Lifo">SELECT * FROM clients LIMIT 1RecordNotFound if no matching record
  9. 9. Retrieving A Single Object - last! - client = Client.last! # => #<Client id: 221, first_name: "Russel">SELECT * FROM clients ORDER BY clients.id DESC LIMIT 1RecordNotFound if no matching record
  10. 10. Retrieving Multiple Objects• Using multiple primary keys• In batches • find_each :batch_size, :start, • find_in_batches :batch_size, :start + find options (except for :order, :limit)
  11. 11. Retrieving Multiple Objects - Using multiple primary keys - # Find the clients with primary keys 1 and 10. client = Client.find([1, 10]) # Or even Client.find(1, 10) # => [#<Client id: 1, first_name: "Lifo">, #<Client id: 10,SELECT * FROM clients WHERE (clients.id IN (1,10))ActiveRecord::RecordNotFound exception
  12. 12. Retrieving Multiple Objects - in Batches - to iterate over a large set of records• find_each : each record to the block individually as a model• find_in_batches : the entire batch to the block as an array of models # This is very inefficient when the users table has thousands of rows. User.all.each do |user|   NewsLetter.weekly_deliver(user) OK to 1,000
  13. 13. RetrievingMultiple Objects - in Batches : find_each -User.find_each do |user|  NewsLetter.weekly_deliver(user)endUser.find_each(:batch_size => 5000) do |user|  NewsLetter.weekly_deliver(user)endUser.find_each(:start => 2000, :batch_size => 5000) do |user|  NewsLetter.weekly_deliver(user)
  14. 14. Retrieving Multiple Objects - in Batches : find_each - Article.find_each { |a| ... } # => iterate over all articles, in chunks of 1000 (the default) Article.find_each(:conditions => { :published => true }, :batch_size => 100 ) { |a| ... } # iterate over published articles in chunks of 100http://archives.ryandaigle.com/articles/2009/2/23/what-s-new-in-edge-rails-batched-find
  15. 15. Retrieving Multiple Objects - in Batches : find_in_batches - # Give add_invoices an array of 1000 invoices at a time Invoice.find_in_batches(:include => :invoice_lines) do | invoices|   export.add_invoices(invoices) endoptions : • :batch_size & :start • options of find method (except :order and :limit)
  16. 16. Retrieving Multiple Objects - in Batches : find_in_batches -Article.find_in_batches { |articles| articles.each { |a| ... } } # => articlesis array of size 1000Article.find_in_batches(:batch_size => 100 ) { |articles| articles.each { |a| ... } } # iterate over all articles in chunks of 100class Article < ActiveRecord::Base scope :published, :conditions => { :published => true }endArticle.published.find_in_batches(:batch_size => 100 ) { |articles| ... } # iterate over published articles in chunks of 100
  17. 17. Conditions - where -• String conditions• Array conditions• Hash conditions
  18. 18. String Conditions Client.where("orders_count = ‘2’")
  19. 19. Array ConditionsClient.where("orders_count = ?", params[:orders])Client.where("orders_count = ? AND locked = ?", params[:orders], false)Client.where("orders_count = #{params[:orders]}")
  20. 20. Array ConditionsClient.where("orders_count = ?", params[:orders])Client.where("orders_count = ? AND locked = ?", params[:orders], false) XClient.where("orders_count = #{params[:orders]}") hacking!!! by SQL injection http://guides.rubyonrails.org/security.html#sql-injection
  21. 21. Array Conditions - Placeholder conditions using symbols -Client.where("created_at >= :start_date AND created_at<= :end_date", {:start_date =>params[:start_date], :end_date => params[:end_date]})
  22. 22. Array Conditions - Range conditions - Client.where(:created_at => (params[:start_date].to_date).. (params[:end_date].to_date))SELECT "clients".* FROM "clients" WHERE("clients"."created_at" BETWEEN 2010-09-29 AND2010-11-30)
  23. 23. Hash Conditions - Equality conditions -Client.where(:locked => true)
  24. 24. Hash Conditions - Range conditions - Client.where(:created_at => (Time.now.midnight - 1.day)..Time.now.midnight)SELECT * FROM clients WHERE (clients.created_at BETWEEN2008-12-21 00:00:00 AND 2008-12-22 00:00:00)
  25. 25. Hash Conditions - Subset conditions - Client.where(:orders_count => [1,3,5])SELECT * FROM clients WHERE (clients.orders_count IN (1,3,5))
  26. 26. OrderingClient.order("created_at")Client.order("created_at DESC")# ORClient.order("created_at ASC")
  27. 27. Selecting ?If the select method is used, all the returning objects will be read only. Client.select("viewable_by, locked") SELECT viewable_by, locked FROM clients ActiveModel::MissingAttributeError: missing attribute: <attribute> Client.select(:name).uniq SELECT DISTINCT name FROM clients query = Client.select(:name).uniq # => Returns unique names query.uniq(false) # => Returns all names, even if there are duplicates
  28. 28. Limit & OffsetClient.limit(5) SELECT * FROM clients LIMIT 5Client.limit(5).offset(30) SELECT * FROM clients LIMIT 5 OFFSET 30
  29. 29. Group Order.select( "date(created_at) as ordered_date, sum(price) as total_price") .group("date(created_at)")SQL SELECT date(created_at) as ordered_date, sum(price) as total_price FROM orders GROUP BY date(created_at)
  30. 30. Having Order.select( "date(created_at) as ordered_date, sum(price) as total_price") .group("date(created_at)") .having("sum(price) > ?", 100)SQL SELECT date(created_at) as ordered_date, sum(price) as total_price FROM orders GROUP BY date(created_at) HAVING sum(price) > 100
  31. 31. Overriding Conditions• except• only• reorder• reverse_order
  32. 32. Overriding Conditions - except -Post.where(id > 10).limit(20).order(id asc).except(:order) SELECT * FROM posts WHERE id > 10 LIMIT 20
  33. 33. Overriding Conditions - only -Post.where(id > 10).limit(20).order(id desc).only(:order, :where) SELECT * FROM posts WHERE id > 10 ORDER BY id DESC
  34. 34. Overriding Conditions - reorder -class Post < ActiveRecord::Base  ..  ..  has_many :comments, :order => posted_at DESCend SELECT * FROM posts WHERE id = 10 ORDER BY posted_at DESCSELECT * FROM posts WHERE id = 10 ORDER BY name
  35. 35. Overriding Conditions - reverse_order - Client.where("orders_count > 10").order(:name).reverse_orderSELECT * FROM clients WHERE orders_count > 10 ORDER BY name DESC Client.where("orders_count > 10").reverse_orderSELECT * FROM clients WHERE orders_count > 10 ORDER BY clients.id DESC
  36. 36. Readonly Objectsclient = Client.readonly.firstclient.visits += 1client.save ActiveRecord::ReadOnlyRecord exception
  37. 37. Locking Records for Update• To prevent “race conditions”• To ensure “atomic updates”• Two locking mechanisms ‣ Optimistic Locking : version control ‣ Pessimistic Locking : DB lock
  38. 38. Optimistic Locking• “lock_version” in DB table (default to 0)• set_locking_column to change column name c1 = Client.find(1) c2 = Client.find(1)   c1.first_name = "Michael" c1.save # increments the lock_version column   c2.name = "should fail"
  39. 39. Optimistic Locking• To turn off, ActiveRecord::Base.lock_optimistically = false• To override the name of the lock_version column class Client < ActiveRecord::Base   set_locking_column :lock_client_column
  40. 40. Pessimistic Locking• A locking mechanism by DB• An exclusive lock on the selected rows• Usually wrapped inside a transaction• Two types of Lock ‣ FOR UPDATE (default, an exclusive lock) ‣ LOCK IN SHARE MODE
  41. 41. Pessimistic Locking Item.transaction do   i = Item.lock.first   i.name = Jones   i.save SQL (0.2ms)   BEGIN Item Load (0.3ms)   SELECT * FROM `items` LIMIT 1 FOR UPDATE Item Update (0.4ms)   UPDATE `items` SET `updated_at` = 2009-02-07 18:05:56, `name` = Jones WHERE `id` = 1 SQL (0.8ms)   COMMIT
  42. 42. Pessimistic Locking Item.transaction do   i = Item.lock("LOCK IN SHARE MODE").find(1)   i.increment!(:views) end item = Item.first item.with_lock do   # This block is called within a transaction,   # item is already locked.   item.increment!(:views)
  43. 43. Joining Tables - Using a String SQL Fragment - Client.joins(LEFT OUTER JOIN addresses ON addresses.client_idSELECT clients.*FROM clientsLEFT OUTER JOIN addressesON addresses.client_id = clients.id
  44. 44. Joining Tables- Using Array/Hash of Named Associations - only with INNER JOIN• a Single Association• Multiple Associations• Nested Associations(Single Level)• Nested Associations(Multiple Level)
  45. 45. Joining Tables - Using Array/Hash of Named Associations - only with INNER JOINclass Category < ActiveRecord::Base  has_many :postsend class Post < ActiveRecord::Base • a Single Association  belongs_to :category  has_many :comments  has_many :tagsend Category.joins(:posts) class Comment < ActiveRecord::Base  belongs_to :post  has_one :guestend SELECT categories.*  FROM categoriesclass Guest < ActiveRecord::Base   INNER JOIN posts  belongs_to :commentend ON posts.category_id = categories.id class Tag < ActiveRecord::Base  belongs_to :post “return a Category object for all categories with posts”end
  46. 46. Joining Tables - Using Array/Hash of Named Associations - only with INNER JOINclass Category < ActiveRecord::Base  has_many :postsend class Post < ActiveRecord::Base • Multiple Associations  belongs_to :category  has_many :comments  has_many :tagsend Post.joins(:category, :comments) class Comment < ActiveRecord::Base  belongs_to :post and  has_one :guest SELECT posts.* FROM postsend    INNER JOIN categoriesclass Guest < ActiveRecord::Base ON posts.category_id = categories.id  belongs_to :comment   INNER JOIN commentsend ON comments.post_id = posts.id class Tag < ActiveRecord::Base “return all posts that have a category and at least one comment”  belongs_to :postend
  47. 47. Joining Tables - Using Array/Hash of Named Associations - only with INNER JOINclass Category < ActiveRecord::Base  has_many :postsend class Post < ActiveRecord::Base • Nested Associations(Single Level)  belongs_to :category  has_many :comments  has_many :tagsend Post.joins(:comments => :guest) class Comment < ActiveRecord::Base  belongs_to :post nested  has_one :guest SELECT posts.* FROM postsend    INNER JOIN commentsclass Guest < ActiveRecord::Base ON comments.post_id = posts.id  belongs_to :comment   INNER JOIN guestsend ON guests.comment_id = comments.id class Tag < ActiveRecord::Base  belongs_to :post “return all posts that have a comment made by a guest”end
  48. 48. Joining Tables - Using Array/Hash of Named Associations - only with INNER JOINclass Category < ActiveRecord::Base  has_many :postsend class Post < ActiveRecord::Base • Nested Associations(Multiple Level)  belongs_to :category  has_many :comments  has_many :tagsend Category.joins(:posts => [{:comments class Comment < ActiveRecord::Base  belongs_to :post  has_one :guestend  SELECT categories.* FROM categoriesclass Guest < ActiveRecord::Base   INNER JOIN posts ON posts.category_id = categories.id  belongs_to :comment INNER JOIN comments ON comments.post_id = posts.idend  INNER JOIN guests ON guests.id = comments.quest_idclass Tag < ActiveRecord::Base INNER JOIN tags ON tags.post_id = posts.id  belongs_to :postend
  49. 49. Joining Tables - Specifying Conditions on the Joined Tables -: using Array and String Conditions time_range = (Time.now.midnight - 1.day)..Time.now.midnight Client.joins(:orders): using nested Hash Conditions time_range = (Time.now.midnight - 1.day)..Time.now.midnight Client.joins(:orders)
  50. 50. 감사합니다.
  51. 51.   ROR Lab.

    Be the first to comment

    Login to see the comments

  • yiqing

    Nov. 23, 2013
  • itclock

    Feb. 20, 2015
  • mazembo

    Sep. 16, 2015

This

Views

Total views

2,264

On Slideshare

0

From embeds

0

Number of embeds

442

Actions

Downloads

35

Shares

0

Comments

0

Likes

3

×