rails active record querying


Retrieving Multiple Objects in Batches


find_each
User.find_each(:batch_size => 5000) do |user|
  NewsLetter.weekly_deliver(user)
end


User.find_each(:batch_size => 5000, :start => 2000) do |user|
  NewsLetter.weekly_deliver(user)
end
:start option allows you to configure the first ID of the sequence if the lowest is not the one you need.
find_each accepts the same options as the regularfind method. However, :order and :limit are needed internally and hence not allowed to be passed explicitly.


Conditions

Client.where("orders_count = ?", params[:orders])
instead of
Client.where("orders_count = #{params[:orders]}")
because of SQL injection

Client.where(:created_at => (params[:start_date].to_date)..(params[:end_date].to_date))

Hash Conditions

Subset Conditions
Client.where(:orders_count => [1,3,5])

Ordering

Client.order("orders_count ASC, created_at DESC")

Selecting Specific Fields

Client.select("viewable_by, locked")

Be careful because this also means you’re initializing a model object with only the fields that you’ve selected. If you attempt to access a field that is not in the initialized record you’ll receive:
ActiveRecord::MissingAttributeError: missing attribute: <attribute>
Client.select("DISTINCT(name)")

Pessimistic Locking
Item.transaction do
  i = Item.lock.first
  i.name = 'Jones'
  i.save
end

Item.transaction do
  i = Item.lock("LOCK IN SHARE MODE").find(1)
  i.increment!(:views)
end

Joining Tables

Client.joins('LEFT OUTER JOIN addresses ON addresses.client_id = clients.id')

Joining a Single Association
Category.joins(:posts)

SELECT categories.* FROM categories
  INNER JOIN posts ON posts.category_id = categories.id

Joining Multiple Associations
Post.joins(:category, :comments)

SELECT posts.* FROM posts
  INNER JOIN categories ON posts.category_id = categories.id
  INNER JOIN comments ON comments.post_id = posts.id


Joining Nested Associations (Single Level)

Post.joins(:comments => :guest)
 Joining Nested Associations (Multiple Level)
Category.joins(:posts => [{:comments => :guest}, :tags])

Specifying Conditions on the Joined Tables

time_range = (Time.now.midnight - 1.day)..Time.now.midnight
Client.joins(:orders).where('orders.created_at' => time_range)

time_range = (Time.now.midnight - 1.day)..Time.now.midnight
Client.joins(:orders).where(:orders => {:created_at => time_range})


Eager Loading Associations


Active Record lets you specify in advance all the associations that are going to be loaded. This is possible by specifying the includes method of the Model.find call. With includes, Active Record ensures that all of the specified associations are loaded using the minimum possible number of queries.

clients = Client.includes(:address).limit(10)
 
clients.each do |client|
  puts client.address.postcode
end

SELECT * FROM clients LIMIT 10
SELECT addresses.* FROM addresses
  WHERE (addresses.client_id IN (1,2,3,4,5,6,7,8,9,10))

Eager Loading Multiple Associations

Post.includes(:category, :comments)

Category.includes(:posts => [{:comments => :guest}, :tags]).find(1)

Dynamic Finders

For every field (also known as an attribute) you define in your table, Active Record provides a finder method. If you have a field called first_name on your Client model for example, you getfind_by_first_name and find_all_by_first_name for free from Active Record. If you have also have a locked field on the Client model, you also get find_by_locked andfind_all_by_locked


If you want to find both by name and locked, you can chain these finders together by simply typingand between the fields for example Client.find_by_first_name_and_locked("Ryan", true)


There’s another set of dynamic finders that let you find or create/initialize objects if they aren’t found.

Finding by SQL

Client.find_by_sql("SELECT * FROM clients
  INNER JOIN orders ON clients.id = orders.client_id
  ORDER clients.created_at desc")

find_by_sql has a close relative called connection#select_allselect_all will retrieve objects from the database using custom SQL just like find_by_sql but will not instantiate them. Instead, you will get an array of hashes where each hash indicates a record.


Existence of Objects

Client.exists?(1)

Client.exists?(1,2,3)
# or
Client.exists?([1,2,3])

Client.where(:first_name => 'Ryan').exists?

Client.exists?

Calculations

 If you want to be more specific and find all the clients with their age present in the database you can use Client.count(:age).

Client.average("orders_count")
minimum maximun sum

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章