I have two models:
Questions:
has_and_belongs_to_many :topics
Topics:
has_and_belongs_to_many :questions
And the associated joining table: questions_topics
How can I write a query to get all topics and their occurrences in the joining table, and sorted by the count (showing by order of the most active topics first)?
So basically I want to be able to do this in a single query:
list = Topics.all
Order list by list.questions.count
Update:
Is there a better rails way to write the following query? (which does appear to give the required result:
Topic.includes(:questions).group('questions_topics.topic_id').references(:questions).order("count(questions_topics.topic_id) DESC")
Related
I have 3 models,
User (has_many :posts)
Post (Belongs_to :user, has_many :categories through: :posts_categories)
Category (has_many :posts through: :posts_categories)
Now, I want to find and order all users who have submitted most posts in a category, how do I achieve this using Ransack search
Eg. For category 'Fashion' I want to fetch & order users by number of user's posts in fashion.
Desired result should give,
Mark (7 posts in fashion)
Dave (5 posts in fashion)
Carla (4 posts in fashion) .. so on
Note: Would prefer a solution that is compatible with postgres
My ransack search in controller
#search = User.all.search(params[:q])
#searchusers = #search.result(distinct: true)
#findusers = #searchusers.joins(posts: :categories)
.where(categories: { id: params['q']['posts_categories_id_eq'] })
.group('users.id')
.order('count(posts.id) desc').page(params[:page]).per(12)
Note: This works perfectly well in SQLite but fails in PG with below error
'PG::Error: SELECT DISTINCT, ORDER BY expressions must appear in select list'
In the following setup a customer has many tags through taggings.
class Customer
has_many :taggings
has_many :tags, through: :taggings
end
class Tagging
belongs_to :tag
belongs_to :customer
end
The query I'm trying to perform in Rails with postgres is to Find all customers that have at least one tag but don't have either of the tags A or B.
Performance would need to be taken into consideration as there are tens of thousands of customers.
Please try the following query.
Customer.distinct.joins(:taggings).where.not(id: Customer.joins(:taggings).where(taggings: {tag_id: [tag_id_a,tag_id_b]}).distinct )
Explanation.
Joins will fire inner join query and will make sure you get only those customers which have at least one tag associated with them.
where.not will take care of your additional condition.
Hope this helps.
Let tag_ids is array of A and B ids:
tag_ids = [a.id, b.id]
Then you need to find the Customers, which have either A or B tag:
except_relation = Customer.
joins(:tags).
where(tags: { id: tag_ids }).
distinct
And exclude them from the ones, which have at least one tag:
Customer.
joins(:tags).
where.not(id: except_relation).
distinct
INNER JOIN, produced by .joins, removes Customer without Tag and is a source of dups, so distinct is needed.
UPD: When you need performance, you probably have to change your DB schema to avoid extra joins and indexes.
You can search examples of jsonb tags implementation.
Get ids of tag A and B
ids_of_tag_a_and_b = [Tag.find_by_title('A').id, Tag.find_by_title('B').id]
Find all customers that have at least one tag but don't have either of the tags A or B.
#Customer.joins(:tags).where.not("tags.id in (?)", ids_of_tag_a_and_b)
Customer.joins(:tags).where.not("tags.id = ? OR tags.id = ?", tag_id_1, tag_id_2)
I have 3 tables: articles, people and person_mentions.
Article model has_many :people, through: person_mentions and so on.
In person_mentions table I have 3 columns article_id, person_id and mention_order. mention_order is an integer.
I need to find all people, who mentioned in article and order them by mention_order, but when I run
#article.people.order(mention_order: :asc)
I get an error
column people.mention_order does not exist
So, I need to make a query from people table with mention_order from person_mentions in it.
Thanks for any help!
Could you try:
#article.people.order("person_mentions.mention_order asc")
I have two models - Blog and BlogTag. Blog has_many :blog_tags and BlogTag belongs_to :blog:
blog.rb
has_many :blog_tags
blog_Tag.rb
belongs_to :blog
I want to query the database to select all blogs that have tags matching in the blog_tags table based on what a user enters in a form field. Something like this:
Blog.where(blog_tags contain [array of tags])
Is there a way to do this with ActiveRecord?
Assuming BlogTag has a column name.
Blog.joins(:blog_tags).where(blog_tags: { name: [array of tags] }).uniq
This would still return Blogs, but only blogs with blog tags whose name is in the array.
Another approach to this is by passing a BlogTag relation into a Blog scope.
Blog.where(id: BlogTag.where(name: tags).select(:blog_id))
So instead of a JOIN, ActiveRecord will construct a subquery
SELECT * FROM blogs WHERE id IN (
SELECT blog_id FROM blog_tags WHERE name IN ('tag1', 'tag2', 'tag3')
)
I have this models:
Event
has_many :incidents
and
Incident
belongs_to :event
I want to getting all events with the incident numbers for each one in one query. In Rails I know exist "group by" and "sum" methods but I don't know how mix both.
thanks.
You need to make a left join, group by object id and count elements:
Events.joins('LEFT JOIN incidents ON incidents.event_id = events.id').group_by('events.id').select('events.*, COUNT(incidents.id) AS incidents_count')
You could also look into counter_cache option.