Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/20.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:当我们需要查询循环内部的关联时,如何删除n+1查询?_Ruby On Rails_Ruby_Ruby On Rails 4 - Fatal编程技术网

Ruby on rails Rails:当我们需要查询循环内部的关联时,如何删除n+1查询?

Ruby on rails Rails:当我们需要查询循环内部的关联时,如何删除n+1查询?,ruby-on-rails,ruby,ruby-on-rails-4,Ruby On Rails,Ruby,Ruby On Rails 4,我的输出结果是代码中有查询,这里只显示基本查询 所以基本上我需要自定义行项目和所有行项目的总和 results = Order.includes(:customer, :line_items).where('completed_at IS NOT NULL') results.each do |result| custom_items_sum = result.line_items.where(line_item_type: 'custom').sum(:amount) total_

我的输出结果是代码中有查询,这里只显示基本查询 所以基本上我需要自定义行项目和所有行项目的总和

results = Order.includes(:customer, :line_items).where('completed_at IS NOT NULL')

results.each do |result|
  custom_items_sum = result.line_items.where(line_item_type: 'custom').sum(:amount)
   total_sum = result.line_items.sum(:amount)
end

在这段代码中,存在n+1查询问题,我尝试添加了include,但肯定不会起作用,因为我们在循环中有另一个查询,任何帮助都将不胜感激???

如果您不想触发循环中的其他查询,您需要避免处理关系的方法,并使用处理集合的方法。试一试

custom_items_sum = result.line_items.
    select { |line_item| line_item.line_item_type == 'custom' }.
    sum(&:amount)
这应该在没有n+1查询的情况下工作


请注意,可以只编写一个查询并避免此计算,但这超出了您的问题范围:

如果您不想触发循环中的其他查询,则需要避免处理关系的方法,并使用处理集合的方法。试一试

custom_items_sum = result.line_items.
    select { |line_item| line_item.line_item_type == 'custom' }.
    sum(&:amount)
这应该在没有n+1查询的情况下工作


请注意,只编写一个查询并避免这种计算是可能的,但这超出了您的问题范围:

Rails从来没有像ORM那样具有足够的健壮性。请改用普通SQL:

results =
  Order.connection.execute <<-SQL
    SELECT order.id, SUM(line_items.amount)
    FROM orders
      JOIN line_items
      ON (line_items.order_id = orders.id)
    WHERE orders.completed_at IS NOT NULL
    GROUP BY orders.id
    HAVING line_items.line_item_type = 'custom'
  SQL

这样,您就可以在一个查询中获得所有中间总和,这比在ruby中执行所有计算要快得多。

Rails从来没有像ORM那样强大过。请改用普通SQL:

results =
  Order.connection.execute <<-SQL
    SELECT order.id, SUM(line_items.amount)
    FROM orders
      JOIN line_items
      ON (line_items.order_id = orders.id)
    WHERE orders.completed_at IS NOT NULL
    GROUP BY orders.id
    HAVING line_items.line_item_type = 'custom'
  SQL

这样,您将在一个查询中获得所有中间总和,这比在ruby中执行所有计算要快得多。

尝试使用作用域块。下面的代码生成非常干净的SQL查询

Order.includes(:line_items).where.not(completed_at: nil).scoping do
   @custom_items_sum = Order.where(line_items: { line_item_type: 'custom' })
                            .sum(:amount)
   @total_sum        = Order.sum(:amount)
end

关于作用域块的文档并不多,但它将您的模型的作用域限定为在此之前发出的ActiveRecord请求:where'completed IS not NULL'并包含:line_项


希望这有帮助!:

尝试使用范围块。下面的代码生成非常干净的SQL查询

Order.includes(:line_items).where.not(completed_at: nil).scoping do
   @custom_items_sum = Order.where(line_items: { line_item_type: 'custom' })
                            .sum(:amount)
   @total_sum        = Order.sum(:amount)
end

关于作用域块的文档并不多,但它将您的模型的作用域限定为在此之前发出的ActiveRecord请求:where'completed IS not NULL'并包含:line_项

希望这有帮助!:

就因为说用原始SQL编写,让我们对rails也这样做吧

order_table = Order.arel_table
line_items_table = LineItem.arel_table
custom_items = Arel::Table.new(:custom_items)
Order.select(
   order_table[Arel.star],
   line_items_table[:amount].sum.as('total_sum'),
   custom_items[:amount].sum.as('custom_items_sum')
).joins(
   order_table.join(line_items_table).on(
     line_items_table[:order_id].eq(order_table[:id])
   ).join(
      Arel::Nodes::As.new(line_items_table,:custom_items), 
      Arel::Nodes::OuterJoin
   ).on( 
      custom_items[:order_id].eq(order_table[:id]).and(
       custom_items[:line_item_type].eq('custom')
      ) 
   ).join_sources
).where(
   order_table[:completed_at].not_eq(nil)
).group(:id)
这将使用以下查询生成一个ActiveRecord::Order对象的关系,其虚拟属性为total_sum和custom_items_sum

SELECT 
  orders.*,
  SUM(line_items.amount) AS total_sum,
  SUM(custom_items.amount) As custom_items_sum
FROM 
  orders
  INNER JOIN line_items ON line_items.order_id = orders.id
  LEFT OUTER JOIN line_items AS custom_items ON custom_items.order_id = orders.id
    AND custom_items.line_item_type = 'custom'
WHERE 
  orders.completed_at IS NOT NULL
GROUP BY 
  orders.id
这应该通过使用2个连接来聚合所需的数据,从而在单个查询中处理请求

就因为说用原始SQL编写,让我们对rails也这样做吧

order_table = Order.arel_table
line_items_table = LineItem.arel_table
custom_items = Arel::Table.new(:custom_items)
Order.select(
   order_table[Arel.star],
   line_items_table[:amount].sum.as('total_sum'),
   custom_items[:amount].sum.as('custom_items_sum')
).joins(
   order_table.join(line_items_table).on(
     line_items_table[:order_id].eq(order_table[:id])
   ).join(
      Arel::Nodes::As.new(line_items_table,:custom_items), 
      Arel::Nodes::OuterJoin
   ).on( 
      custom_items[:order_id].eq(order_table[:id]).and(
       custom_items[:line_item_type].eq('custom')
      ) 
   ).join_sources
).where(
   order_table[:completed_at].not_eq(nil)
).group(:id)
这将使用以下查询生成一个ActiveRecord::Order对象的关系,其虚拟属性为total_sum和custom_items_sum

SELECT 
  orders.*,
  SUM(line_items.amount) AS total_sum,
  SUM(custom_items.amount) As custom_items_sum
FROM 
  orders
  INNER JOIN line_items ON line_items.order_id = orders.id
  LEFT OUTER JOIN line_items AS custom_items ON custom_items.order_id = orders.id
    AND custom_items.line_item_type = 'custom'
WHERE 
  orders.completed_at IS NOT NULL
GROUP BY 
  orders.id

这应该通过使用2个连接来聚合所需的数据,从而在单个查询中处理请求

@Urus实际上这只是实现的一小部分,我正在使用ajax datatables rails和多个查询。此时,由于其他复杂性,此解决方案更可取。否则,实现原始查询是最好的解决方案。另外,它应该是.sum&:amount而不是.sum:amount。显然,在这里,单个查询是最好的解决方案。嗯,虽然不是原始的,但完全有可能编写一个活动记录为well@Urus实际上,这只是实现的一小部分,我正在使用ajax datatables rails和多个查询。此时,由于其他复杂性,此解决方案更可取。否则,实现原始查询是最好的解决方案。另外,它应该是.sum&:amount而不是.sum:amount。显然,在这里,单个查询是最好的解决方案。好吧,虽然不是原始的,但完全有可能写一个有活动记录的,在这篇文章中,我将如何得到所有行项目的总和呢?此查询将为我提供订单及其自定义行项目的总和?总和是一个调用,只需在Rails中执行,或编写另一个查询。@AlekseiMatiushkin仅仅因为Rails没有像大多数情况下那样为您提供这种类型的银匙,并不意味着没有原始sql就无法完成。Arel是一个非常强大和高效的SQL生成器,允许真正基于方法的实现具有充分的灵活性。它还直接集成到基于AR的查询中,在本文中,我将如何获得所有行项目的总和?此查询将为我提供订单及其自定义行项目的总和?总和是一个调用,只需在Rails中执行,或编写另一个查询。@AlekseiMatiushkin仅仅因为Rails没有像大多数情况下那样为您提供这种类型的银匙,并不意味着没有原始sql就无法完成。Arel是一个非常强大和高效的SQL生成器,允许真正基于方法的实现具有充分的灵活性。它还直接集成到基于AR的查询中