I have a record set that includes a date field, and want to determine how many unique dates are represented in the record set.
Something like:
Record.find(:all).date.unique.count
but of course, that doesn't seem to work.
This has changed slightly in rails 4 and above :distinct => true is now deprecated. Use:
Record.distinct.count('date')
Or if you want the date and the number:
Record.group(:date).distinct.count(:date)
What you're going for is the following SQL:
SELECT COUNT(DISTINCT date) FROM records
ActiveRecord has this built in:
Record.count('date', :distinct => true)
Outside of SQL:
Record.find(:all).group_by(&:date).count
ActiveSupport's Enumerable#group_by is indispensable.
the latest #count on rails source code only accept 1 parameter.
see: http://api.rubyonrails.org/classes/ActiveRecord/Calculations.html#method-i-count
so I achieved the requirement by
Record.count('DISTINCT date')
Detailing the answer:
Post.create(:user_id => 1, :created_on => '2010-09-29')
Post.create(:user_id => 1, :created_on => '2010-09-29')
Post.create(:user_id => 2, :created_on => '2010-09-29')
Post.create(:user_id => null, :created_on => '2010-09-29')
Post.group(:created_on).count
# => {'2010-09-29' => 4}
Post.group(:created_on).count(:user_id)
# => {'2010-09-29' => 3}
Post.group(:created_on).count(:user_id, :distinct => true) # Rails <= 3
Post.group(:created_on).distinct.count(:user_id) # Rails = 4
# => {'2010-09-29' => 2}
As I mentioned here, in Rails 4, using (...).uniq.count(:user_id) as mentioned in other answers (for this question and elsewhere on SO) will actually lead to an extra DISTINCT being in the query:
SELECT DISTINCT COUNT(DISTINCT user_id) FROM ...
What we actually have to do is use a SQL string ourselves:
(...).count("DISTINCT user_id")
Which gives us:
SELECT COUNT(DISTINCT user_id) FROM ...
Also, make sure you have an index on the field in your db, or else that query will quickly become sloooow.
(It's much better to do this in SQL, otherwise you pull the entire db table into memory just to answer the count.)
Related
I am error in the 2nd line of the code here, I have a column user_id in the Estate table. What am I doing wrong here ?
myestate = Estate.where(:Mgmt => current_user.Company)
#managements = User.where(:id => myestate.user_id)
where is returning an ActiveRecord::Relation object. Because where(:mgmt => current_user.company) could return 0, 1, or Many records, you have to tell the query what you'd like from it.
Try:
myestate = Estate.where(:Mgmt => current_user.Company).first
#managements = User.where(:id => myestate.user_id)
Getting familiar with AREL and how it works is highly recommended. You can find great info on the github page or the Active Record Query Guide
I have this query that does what I want which is to return true if any of the materials is comparable in the material groups list.
mgroup.MaterialGroups.Select(x => x.Materials
.Any(m => Convert.ToBoolean(m.Comparable)))
.Any(x => x.Equals(true))
What I would like to add to this query is to also include this one.
mgroup.Materials.Any(m => Convert.ToBoolean(m.Comparable));
How can I combine mgroup and it's materialgroups together in the query so I can select both of their Materials? Thanks.
EDIT - After fighting with LINQ for awhile I broke down and just combined as
mgroup.Materials.Any(m => Convert.ToBoolean(m.Comparable) ||
mgroup.MaterialGroups.Select(x => x.Materials
.Any(c => Convert.ToBoolean(c.Comparable)))
.Any(x => x.Equals(true)))
It works as expected but it's horribly long and it's embedded in an Asp.net MVC view to makes things even worse. If anyone can simplify this that would be amazing.
P.S.- If you are wondering why I added the extra .Any(x => x.Equals(true) at the end it's because without it the query returns an IEnumerable of bools instead of bool.
IEnumerable<Material> allMaterials =
mgroup.Materials.Concat(
mgroup.MaterialGroups.SelectMany(group => group.Materials));
bool result = allMaterials.Any(m => Convert.ToBoolean(m.Comparable));
I had this query in Mongoid2 that was working fine:
GlobalWord.collection.update({"_id" => "foo"}, {"$inc" => {:count => 1}}, :upsert => true)
If it finds the GlobalWord with the id foo, then it updates its count by one, otherwise it creates a document with the id foo and a count of one. I didn't find an equivalent for that in mongoid3.
edit: I need the query to be atomic
I believe this should work:
GlobalWord.find("_id": "foo").upsert("$inc": {count: 1})
I didn't test it, though. There's no MongoDB on my phone :)
I used
GlobalWord.create(:id => word).inc(:count, 1)
which seems to be atomic
From the docs & rdoc
GlobalWord.new(id: word).upsert("$inc" => {count: 1})
I have a linq query that returns a list of employees and a job title.
I need to sort it by job title but have the ones that do not have any employees in the output list first.
Example sorted:
- Driver List{0}
- Attendant List{71}
- Pilot List{19}
The driver is first because it has nothing in the list and then it is sorted by title.
I am just curious what do you think would be my best option to accomplish that?
Thanks
Something like:
var query = employees.OrderBy(x => x.Subordinates.Any() ? 1 : 0)
.ThenBy(x => x.JobTitle);
You could also use the fact that false sorts earlier than true:
var query = employees.OrderBy(x => !x.Subordinates.Any())
.ThenBy(x => x.JobTitle);
... but that's a little bit less obvious, IMO.
Something like:
Jobs.OrderBy(j => j.Eployees.Count()).ThenBy(j => j.Name);
What is the best way to find records with duplicate values in a column using ruby and the new Activerecord?
Translating #TuteC into ActiveRecord:
sql = 'SELECT id,
COUNT(id) as quantity
FROM types
GROUP BY name
HAVING quantity > 1'
#=>
Type.select("id, count(id) as quantity")
.group(:name)
.having("quantity > 1")
Here's how I solved it with the AREL helpers, and no custom SQL:
Person.select("COUNT(last_name) as total, last_name")
.group(:last_name)
.having("COUNT(last_name) > 1")
.order(:last_name)
.map{|p| {p.last_name => p.total} }
Really, it's just a nicer way to write the SQL. This finds all records that have duplicate last_name values, and tells you how many and what the last names are in a nice hash.
I was beating my head against this problem with a 2016 stack (Rails 4.2, Ruby 2.2), and got what I wanted with this:
> Model.select([:thing]).group(:thing).having("count(thing) > 1").all.size
=> {"name1"=>5, "name2"=>4, "name3"=>3, "name4"=>2, "name5"=>2}
With custom SQL, this finds types with same values for name:
sql = 'SELECT id, COUNT(id) as quantity FROM types
GROUP BY name HAVING quantity > 1'
repeated = ActiveRecord::Base.connection.execute(sql)
In Rails 2.x, select is a private method of AR class. Just use find():
klass.find(:all,
:select => "id, count(the_col) as num",
:conditions => ["extra conditions here"],
:group => 'the_col',
:having => "num > 1")
Here is a solution that extends the other answers to show how to find and iterate through the records grouped by the duplicate field:
duplicate_values = Model.group(:field).having(Model.arel_table[:field].count.gt(1)).count.keys
Model.where(field: duplicate_values).group_by(&:field).each do |value, records|
puts "The records with ids #{records.map(&:id).to_sentence} have field set to #{value}"
end
It seems a shame this has to be done with two queries but this answer confirms this approach.