Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 包括/连接rails 4中的机箱_Ruby On Rails_Ruby On Rails 4_Activerecord - Fatal编程技术网

Ruby on rails 包括/连接rails 4中的机箱

Ruby on rails 包括/连接rails 4中的机箱,ruby-on-rails,ruby-on-rails-4,activerecord,Ruby On Rails,Ruby On Rails 4,Activerecord,我的产品和类别模型之间存在habtm关系。 我正在尝试编写一个查询,搜索至少有两个类别的产品 我用以下代码实现了它: p = Product.joins(:categories).group("product_id").having("count(product_id) > 1") p.length # 178 p2 = Product.includes(:categories).joins(:categories).group("product_id").having("count(p

我的
产品
类别
模型之间存在
habtm
关系。 我正在尝试编写一个查询,搜索至少有两个类别的产品

我用以下代码实现了它:

p = Product.joins(:categories).group("product_id").having("count(product_id) > 1")
p.length # 178
p2 = Product.includes(:categories).joins(:categories).group("product_id").having("count(product_id) > 1")
p2.length # 178 - I compared and the objects are the same as last query
但是,在对它进行迭代时,每次我调用
product.categories
,它都会对数据库进行新的调用-这不太好我希望阻止这些调用并获得相同的结果。做了更多的研究后,我发现我可以将(
includes
)包含在我的
categories
表中,它会将所有表加载到内存中,因此在迭代时不必再次调用数据库。因此,我使用以下代码实现了它:

p = Product.joins(:categories).group("product_id").having("count(product_id) > 1")
p.length # 178
p2 = Product.includes(:categories).joins(:categories).group("product_id").having("count(product_id) > 1")
p2.length # 178 - I compared and the objects are the same as last query
以下是我感到困惑的地方:

p.first.eql? p2.first # true
p.first.categories.eql? p2.first.categories # false
p.first.categories.length # 2
p2.first.categories.length # 1

为什么使用
includes
查询,我得到了正确的对象,但没有得到正确的
类别
关系?

这与
方法有关。您的
p2
仅包含每个产品的第一个类别

您可以将其分为两个查询:

product_ids = Product.joins(:categories).group("product_id").having("count(product_id) > 1").pluck(:product_id)

result = Product.includes(:categories).find(product_ids)

是的,你点击了数据库两次,但至少你在迭代时不去数据库。

这与
方法有关。您的
p2
仅包含每个产品的第一个类别

您可以将其分为两个查询:

product_ids = Product.joins(:categories).group("product_id").having("count(product_id) > 1").pluck(:product_id)

result = Product.includes(:categories).find(product_ids)

是的,你点击了数据库两次,但至少你在迭代时没有进入数据库。

你必须知道,
包含
不能很好地处理连接(
连接
只会抑制前者)

另外,当您
包含
时,关联
ActiveRecord
会确定它是使用
eager\u load
(使用左连接)还是
预加载
(使用单独的查询)。Includes只是其中一个的包装器

问题是,
preload
可以很好地处理连接!所以你可以这样做:

products = Product.preload(:categories). # this will trigger a separate query
               joins(:categories).       # this will build the relevant query
               group("products.id").
               having("count(product_id) > 1").
               select("products.*")

请注意,这也会两次命中数据库,但您不会有任何O(n)查询。

您必须知道,
includes
不能很好地处理联接(
joins
只会抑制前者)

另外,当您
包含
时,关联
ActiveRecord
会确定它是使用
eager\u load
(使用左连接)还是
预加载
(使用单独的查询)。Includes只是其中一个的包装器

问题是,
preload
可以很好地处理连接!所以你可以这样做:

products = Product.preload(:categories). # this will trigger a separate query
               joins(:categories).       # this will build the relevant query
               group("products.id").
               having("count(product_id) > 1").
               select("products.*")

请注意,这也会两次命中数据库,但不会有任何O(n)查询。

这就像一个符咒。非常感谢@Jason,他工作得很有魅力。非常感谢@JasonLove您的解决方案和解释@charlysisto。Love您的解决方案和解释@charlysisto。