How to fetch parents based on their child's records


How to fetch parents based on their child's records



I have two models like



company.rb


class Company < ApplicationRecord
has_many :posts
end



post.rb


class Post < ApplicationRecord
belongs_to :company

scope :notClosed, -> {where(closed: false)}
scope :published, -> {where(published: true)}
end



I want to fetch companies which carries at least one post with matching post scope


scope



Currently my queries is


Company.where(company_type: "Private").all



It's return all companies but how to modify this query for my needs.





I want to fetch companies which carries at least one post, actually, an INNER JOIN keyword would return the companies with posts associated, you can append a distinct statement to get non-repeated records. Can you explain further what you're trying to do?
– Sebastian Palma
Jul 2 at 3:55






I don't want to fetch company which post record zero based on post scope like notClosed and published @SebastianPalma
– jesica
Jul 2 at 3:58


scope


notClosed


published





So, try Company.joins(:posts).distinct.merge(Post.notClosed).
– Sebastian Palma
Jul 2 at 4:00


Company.joins(:posts).distinct.merge(Post.notClosed)





Hey @SebastianPalma, maybe it's working see the query SELECT DISTINCT "companies".* FROM "companies" INNER JOIN "posts" ON "posts"."company_id" = "companies"."id" WHERE "companies"."company_type" = ? AND "posts"."closed" = ? AND "posts"."published" = ? LIMIT ? [["company_type", "Private"], ["closed", "f"], ["published", "t"], ["LIMIT", 11]], can you please suggest me about speed performance issue because my database is only posts over one million, I think you can post this as a answer.
– jesica
Jul 2 at 4:13


SELECT DISTINCT "companies".* FROM "companies" INNER JOIN "posts" ON "posts"."company_id" = "companies"."id" WHERE "companies"."company_type" = ? AND "posts"."closed" = ? AND "posts"."published" = ? LIMIT ? [["company_type", "Private"], ["closed", "f"], ["published", "t"], ["LIMIT", 11]]




3 Answers
3


published_post_companies = Company.joins(:posts).distinct.merge(Post.published)
notClosed_post_companies = Company.joins(:posts).distinct.merge(Post.notClosed)



This will get you all Companies (once) with at least one post that's "not closed":


Company.includes(:posts).joins(:posts).where(company_type: "Private").merge(Post.notClosed)





It's execution time is to long
– jesica
Jul 2 at 4:17





Do you have database indices on all the relevant columns, i. e. company.company_type, post,company_id, post.closed, post.published?
– MattW.
Jul 2 at 8:10



The explicit Rails way: get the IDs of companies from the Post scope then query on those IDs:


Post


Company.where(id: Post.published.pluck(:company_id).uniq)



Note, however, this might be expensive if you have a huge amount of posts. There could be a more efficient way using SQL.





My database is only posts over one million
– jesica
Jul 2 at 4:01





where(id: Post.published.select(:company_id)) would serve you better, that would do a subquery inside the database rather than pulling a bunch of data out of the database and then sending it back. It also neatly avoids duplicates that JOINs can introduce.
– mu is too short
Jul 2 at 4:02



where(id: Post.published.select(:company_id))





Hello Sir @muistooshort, I have several condition like type: "private", notClosed, published & not expired how the query based on that condition, can you please suggest me.
– jesica
Jul 2 at 4:10


type: "private"


notClosed


published


expired





@muistooshort TIL, ty for the comment.
– Tamer Shlash
Jul 2 at 4:12






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Rothschild family

Cinema of Italy