What is the difference between pluck and collect in Rails?
pluck
is on the db level. It will only query the particular field. See this.
When you do:
User.first.gifts.collect(&:id)
You have objects with all fields loaded and you simply get the id
thanks to the method based on Enumerable.
So:
if you only need the
id
with Rails 4, useids
:User.first.gifts.ids
if you only need some fields with Rails 4, use
pluck
:User.first.gifts.pluck(:id, :name, ...)
if you only need one field with Rails 3, use
pluck
:User.first.gifts.pluck(:id)
if you need all fields, use
collect
if you need some fields with Rails 4, still use
pluck
if you need some fields with Rails 3, use
select
andcollect
Which one is faster between map, collect, select and pluck?
Usage of any of these methods requires different use cases:
Both select
and pluck
make SQL's SELECT
of specified columns (SELECT "users"."name" FROM "users"
). Hence, if you don't have users
already fetched and not going to, these methods will be more performant than map/collect
.
The difference between select
and pluck
:
- Performance: negligible when using on a reasonable number of records
- Usage:
select
returns the list of models with the column specified,pluck
returns the list of values of the column specified. Thus, again, the choice depends on the use case.
collect/map
methods are actually aliases, so there's no difference between them. But to iterate over models they fetch the whole model (not the specific column), they make SELECT "users".* FROM "users"
request, convert the relation to an array and map over it.
This might be useful, when the relation has already been fetched. If so, it won't make additional requests, what may end up more performant than using pluck
or select
. But, again, must be measured for a specific use case.
ActiveRecords select(:id).collect vs. pluck(:id) methods: Why is pure AR pluck slower?
Your benchmark is inaccurate. First of all, as you can see, both executions on the database side triggers the same query
SELECT "articles"."id" FROM "articles"
Therefore, the database time should be considered irrelevant. Clearly the two queries had different execution time as shown by the console, but this is normal as if you run the same query 100 times the execution time can be different each time as it depends by a variety of variables such as the machine load, the database state, etc.
Since the database execution time can be considered equivalent, it's irrelevant for the benchmark.
Therefore, what you need to compare is the Ruby execution time and allocation. Pluck is supposed to be faster and more lightweight as compared to collect
it doesn't allocate ActiveRecord objects, rather it returns only the selected values.
If you really want to benchmark the methods, you should mock the database time (which is clearly variable but irrelevant for this benchmark) and only benchmark allocation and the two different Ruby methods.
Long story short, pluck
is generally more efficient.
Pluck in a selected object
Pluck
will not work in that case. So instead of using pluck
:
User.find([1,2,3]).pluck(:name)
Try using map
:
User.find([1,2,3]).map(&:name)
What is simplest way to convert :pluck or :collect results to array of strings in Rails?
Product.first.records.pluck(:price).map(&:to_s)
`Pluck` but for a single retrieved record?
Seems like there are a decent number of options but generally speaking what you are talking about is a presenter pattern.
If you wanted a Hash
from your model that would be simple:
def details
attributes.slice('id', 'oauth_id', 'oauth_expires_at',
'sync_emails', 'last_email_sync', 'manual_query')
end
If you wanted a more formal object then this is where the presenter comes in (there are many libraries for this but we will just write our own for the sake of this question)
class OauthUserPresenter
WHITELIST = %w(id oauth_id oauth_expires_at sync_emails last_email_sync manual_query)
WHITELIST.each {|attr| define_method(attr) {@_exposed_attributes[attr]}}
def initialize(user)
@_exposed_attributes = user.attributes.slice(WHITELIST)
end
def to_hash #this will allow for #as_json and #to_json
@_exposed_attributes
end
end
Then you can call as
o = OauthUserPresenter.new(OauthUser.first)
now o
is technically a read only presenter object. None of the other attributes will be exposed and you can still access the methods as id
, oauth_id
, etc.
Presenters also allow you to add other methods without cluttering the model e.g.
class OauthUserPresenter
def expired?
begin
Time.parse(oauth_expires_at) <= Time.now
rescue TypeError, ArgumentError #handle nil, empty string, and invalid times
true
end
end
end
Rails Query group and pluck to Return Array of IDs grouped by another attribute?
At least in newer versions of Rails and PostgreSQL this is possible:
pairs = Model.select(:account_id, 'array_agg(id)')
.group(:account_id)
.pluck(:account_id, 'array_agg(id)')
This returns:
[
[1, [535, 536]],
[2, [542, 567, 588]],
]
which can be converted into a hash:
Hash[*pairs.flatten(1)]
{
1 => [535, 536],
2 => [542, 567, 588],
}
array_agg
is a PostgreSQL function, but I assume MySQL's GROUP_CONCAT
would work, too.
Rails .pluck on joined tables with columns of the same name returns one value and then nil
This is a bit tricky. Since there's an INNER JOIN
the query produces only one id
in this instance. You can actually form query the other way around:
Feature.joins(:experiment)
.where(features: { experiment_id: 1 })
.pluck(:id, :experiment_id)
Or:
Feature.joins(:experiment)
.where(experiments: { id: 1 })
.pluck(:id, :experiment_id)
Related Topics
How to Use Global Variables or Constant Values in Ruby
Find Unused Code in a Rails App
Rails Console: Reload! Not Reflecting Changes in Model Files? What Could Be Possible Reason
How to Call a Controller'S Method from a View (As We Call from Helper Ideally)
Ruby - Net/Http - Following Redirects
Imagemagick - "Core_Rl_Magick_.Dll Not Found" or How to Install Rmagick on Windows With Ruby 1.9.2
Exporting an Environment Variable in Ruby
How to Change the Default Path of View Files in a Rails 3 Controller
Undefined Method Raise_In_Transactional_Callbacks=' for Activerecord::Base:Class (Nomethoderror)
Rvm Warning! Path Is Not Properly Set Up
Fork Child Process with Timeout and Capture Output
Are Crlf Lines Ok in a Rails Project Deployed on Linux
Error Sudo: Gem: Command Not Found
Has Anyone Tried Installing Ruby & Rubygems from Source on Ubuntu (Preferably Ubuntu 9)
Can't Install Rails on MAC Os Catalina
Paperclip::Errors::Missingrequired
validatorerror With Rails 4