Rails:查询子孙,运行子方法,SQL孙子SUM——结果是数组?
Rails: query children and grandchildren, run method on child, SQL SUM on grandchildren -- resulting in array?
型号:
class Category < ApplicationRecord
has_many :inventories
has_many :stocks, through: :inventories
end
class Inventory < ApplicationRecord
belongs_to :category
has_many :stocks
end
class Stock < ApplicationRecord
belongs_to :inventory
end
目标:
实现高效的 ActiveRecord 查询,构建这样的数组:
[
{ name: "Supplies", count: 10.00, total_value: 40.00 },
{ name: "Materials", count: 25.00, total_value: 30.00 }
]
名称 -> 只是库存模型中的一个常规属性
count -> 在 stocks table
的 :count 列上的 SQL SUM
total_value -> 来自 Inventory 模型中进行一些数学计算的方法
这可能完全是天方夜谭,但我有一个很大的数据集,所以我正在努力使它变得非常高效。有什么想法吗?
编辑以回答问题:
total_value 是 Inventory 上的一个方法,然后调用 Stock 上的一个方法的总和:
def total_value
stocks.map do |stock|
stock.total_cost
end.sum
end
total_cost 是 Stock 上的一种方法:
def total_cost
cost_per_unit * count
end
给你:query = Inventory.group(:id, :name).select(:id, :name).left_joins(:stocks).select("SUM(stocks.count) AS count").select("SUM(stocks.cost_per_unit * stocks.count) AS total_value")
query.as_json
给了你要找的东西。
您还可以通过 find_each
访问数据:query.find_each { |record| puts "record #{record.name} has a total value of #{record.total_value}" }
如果你想避免在SQL中重复total_value
的逻辑,你必须加载股票记录,如果有很多,这会大大减慢计算速度:
升级模型
class Inventory < ApplicationRecord
def stocks_count
stocks.sum(&:count)
end
def total_value
stocks.sum(&:total_cost)
end
end
和查询
Inventory.preload(:stocks).map do |inventory|
{
name: inventory.name,
count: inventory.stocks_count,
total_value: inventory.total_value
}
end
如果您想最大程度地优化查询,您可以考虑在 inventories
上缓存 2 列 total_value
和 stocks_count
table。每当其中一个库存发生变化(创建、删除、更新)时,您都会更新它们。它更难维护,但这是最快的选择。
型号:
class Category < ApplicationRecord
has_many :inventories
has_many :stocks, through: :inventories
end
class Inventory < ApplicationRecord
belongs_to :category
has_many :stocks
end
class Stock < ApplicationRecord
belongs_to :inventory
end
目标:
实现高效的 ActiveRecord 查询,构建这样的数组:
[
{ name: "Supplies", count: 10.00, total_value: 40.00 },
{ name: "Materials", count: 25.00, total_value: 30.00 }
]
名称 -> 只是库存模型中的一个常规属性
count -> 在 stocks table
的 :count 列上的 SQL SUMtotal_value -> 来自 Inventory 模型中进行一些数学计算的方法
这可能完全是天方夜谭,但我有一个很大的数据集,所以我正在努力使它变得非常高效。有什么想法吗?
编辑以回答问题:
total_value 是 Inventory 上的一个方法,然后调用 Stock 上的一个方法的总和:
def total_value
stocks.map do |stock|
stock.total_cost
end.sum
end
total_cost 是 Stock 上的一种方法:
def total_cost
cost_per_unit * count
end
给你:query = Inventory.group(:id, :name).select(:id, :name).left_joins(:stocks).select("SUM(stocks.count) AS count").select("SUM(stocks.cost_per_unit * stocks.count) AS total_value")
query.as_json
给了你要找的东西。
您还可以通过 find_each
访问数据:query.find_each { |record| puts "record #{record.name} has a total value of #{record.total_value}" }
如果你想避免在SQL中重复total_value
的逻辑,你必须加载股票记录,如果有很多,这会大大减慢计算速度:
升级模型
class Inventory < ApplicationRecord
def stocks_count
stocks.sum(&:count)
end
def total_value
stocks.sum(&:total_cost)
end
end
和查询
Inventory.preload(:stocks).map do |inventory|
{
name: inventory.name,
count: inventory.stocks_count,
total_value: inventory.total_value
}
end
如果您想最大程度地优化查询,您可以考虑在 inventories
上缓存 2 列 total_value
和 stocks_count
table。每当其中一个库存发生变化(创建、删除、更新)时,您都会更新它们。它更难维护,但这是最快的选择。