Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding records with two specific records in another table

I have a Product model that has_and_belongs_to_many :taxons, and I want to find all products that are in specific taxons.

For example, if a product belongs to both the "Ruby on Rails" and "Shirts" taxon, I want that product to be returned in the dataset, but not if it only belongs to either "Ruby on Rails" or "Shirts"

like image 885
Ryan Bigg Avatar asked Jun 05 '12 03:06

Ryan Bigg


People also ask

How can I get matching records from two tables?

(INNER) JOIN : Returns records that have matching values in both tables. LEFT (OUTER) JOIN : Returns all records from the left table, and the matched records from the right table. RIGHT (OUTER) JOIN : Returns all records from the right table, and the matched records from the left table.

How do you fetch records that are present in one table but not in another table?

How to Select All Records from One Table That Do Not Exist in Another Table in SQL? We can get the records in one table that doesn't exist in another table by using NOT IN or NOT EXISTS with the subqueries including the other table in the subqueries.

How do you find non matching records between two tables?

The second way to find non-matching records between tables is to use NOT in conjunction with the IN operator. The IN operator allows you to specify multiple values in a WHERE clause, much like a string of ORs chained together.


2 Answers

I had this problem a while back, thankfully there is a nice solution.

def self.has_taxons(taxons)
  id = arel_table[:id]
  Product.joins(:taxons).where(taxons: { name: taxons }).group(id).having(id.count.eq(taxons.size))
end
like image 113
Samuel Avatar answered Nov 15 '22 00:11

Samuel


This answer from @samuel is exactly what I was looking for, but I wanted to be able to still supply keywords to the search while filtering by Taxon1 AND Taxon2 and TaxonN. I don't ever need to do a Taxon1 OR Taxon2 search, so I made the following customizations. There might be a less hacky way to do this, but it works great for me.

I added a new product scope in /app/models/spree/product_decorator.rb

Spree::Product.class_eval do
    add_search_scope :in_all_taxons do |*taxons|
        taxons = get_taxons(taxons)
        id = arel_table[:id]
        joins(:taxons).where(spree_taxons: { id: taxons }).group(id).having(id.count.eq(taxons.size))
    end
end

Then used the new scope by adding it to /app/models/spree/base_decorator.rb

Spree::Core::Search::Base.class_eval do
    def get_base_scope
        base_scope = Spree::Product.active
        base_scope = base_scope.in_all_taxons(taxon) unless taxon.blank?
        base_scope = get_products_conditions_for(base_scope, keywords)
        base_scope = add_search_scopes(base_scope)
        base_scope
    end
end

Now I can use the standard search helper to retrieve products (which means I can still supply keywords, etc along with the multiple taxons):

# taxon_ids is an array of taxon ids
@searcher = build_searcher(params.merge(:taxon => taxon_ids))
@products = @searcher.retrieve_products

This works for me and felt pretty painless. However, I'm open to better options.

like image 21
Jamie Stephens Avatar answered Nov 15 '22 01:11

Jamie Stephens