Spree: intersection between taxons

百般思念 提交于 2019-12-13 03:34:34

问题


Is it possible to query for products that belongs to multiple taxons? Like a math intersection.

For example: I sell books that belongs to taxon Universities > ASU, and belongs to taxon Course > Engineering

I would like to be able to query for all books that belongs to the ASU Engineering path. Something like

Spree::Product.in_taxon(asu_taxon).in_taxon(eng_taxon)

回答1:


There's a few ways to do this. I'm going to use the spree sandbox data, so you can try the results if you're interested.

First, we can iterate through all products, and check their taxons using pure Ruby:

Spree::Product.all.select do |product|
  taxon_names = product.taxons.map(&:name)  
  taxon_names.include?("Rails") && taxon_names.include?("Bags")  
end

The downside to this is that it has to retrieve all of the products from the database, and then all of their taxons in separate queries. It'll be pretty slow if you have a decent number of products.

We can make that a little bit better with:

Spree::Product.joins(:taxons).includes(:taxons).where(spree_taxons: { name: ["Rails", "Bags"]}).all.select do |product|
  taxon_names = product.taxons.map(&:name)  
  taxon_names.include?("Rails") && taxon_names.include?("Bags")  
end

This will only get products which belong to one of the two taxons, and retrieve all of the taxon data using a single query. It'll be much faster, but we can do better...kind of...

You can use SQL joins in order to join the table multiple times in order to reduce this to one query which retrieves all of the records that you want:

Spree::Product
  .joins('INNER JOIN spree_products_taxons rails_join ON (spree_products.id = rails_join.product_id)')
  .joins('INNER JOIN spree_taxons rails_taxon ON (rails_join.taxon_id = rails_taxon.id AND rails_taxon.name == "Rails")')
  .joins('INNER JOIN spree_products_taxons bags_join ON (spree_products.id = bags_join.product_id)')
  .joins('INNER JOIN spree_taxons bags_taxon ON (bags_join.taxon_id = bags_taxon.id AND bags_taxon.name == "Bags")')

It's a bit ugly, but it's the fastest way to get the data, as you get only the products you want with a single SQL query.

There might be less bad ways to do it, but this is the best I've got!




回答2:


You could try Spree::Product.joins('INNER JOIN spree_products_taxons rails_join ON (spree_products.id = rails_join.product_id)').joins('INNER JOIN spree_taxons rails_taxon ON (rails_join.taxon_id = rails_taxon.id AND rails_taxon.name NOT IN ("Hide", "Old") )')




回答3:


I have the same use case and ended up doing this:

Product.joins(:classifications)
  .where(classifications: {taxon_id: taxon_ids})
  .group('products.id')
  .having('COUNT("products"."id") = ?', taxon_ids.count)

Hope it helps



来源:https://stackoverflow.com/questions/22790067/spree-intersection-between-taxons

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!