Rails (活动记录) - 无法使用连接和全局总和进行查询,而没有重复项



我使用了一个带有多个用户集过滤器的查询,以便在Rails应用程序中显示发票列表。其中一个过滤器在一个单独表的列上添加了where条件,该表需要双重联接才能访问(估计-通过项目-)。

scope :by_seller, lambda {|user_id|
joins(project: :estimates)
.where(estimates: {:user_id => user_id}) unless user_id.blank?
}

此外,我使用Rails的聚合方法"sum"来计算发票的总额,@invoits.sum(:total_cache),其中total_cachie是数据库中的一个缓存列,专门设计用于以性能方式执行这种合计。

@invoices.sum(:total_cache)

我的问题是,考虑到我需要双重联接才能通过项目访问估算,并且每个发票都属于一个项目,但一个项目可能有多个估算,联接操作会导致重复记录,因此我的发票表多次显示一些发票(与其项目的估算数量一样多)。这会导致发票表中有重复的记录,并且总和值不正确,因为它将某些发票总额相加了N次。

过滤行为很好,因为我的意图是由在发票项目中做出任何估计的用户进行过滤。然而,问题是,当我试图通过添加一个组("发票.id")来避免重复时——我总是这样解决这种情况——最终求和操作不会返回发票总额的总和,而是每个发票的分组总和(完全无用)。

我找到的唯一解决方法是包含group子句,并在纯ruby代码中执行求和,将集合视为数组,IMHO效率非常低,因为有大量发票:

@invoices.map(&:total_cache).inject(0, &:+)

有没有一种方法可以让我在没有重复的情况下获得唯一的发票ActiveRecord集合,这样我就可以调用聚合和方法并获得Postgres计算的总额?

当然,如果我的基本想法有什么问题,我完全愿意听到!这是一个相当复杂的查询(为了这里的问题,我简化了它),我相信可以有很多方法!

谢谢大家!

我不确定这比在ruby代码中求和要"慢"或"快"多少。但是,如果您仍然想保留一个ActiveRecord::Relation对象,那么您可以执行以下操作。我在本地Rails项目中复制了您的设置环境。

user = User.first
Invoice.where(
id: Invoice.by_seller(user.id).select(:id)
).sum(:total_cache)
# (1.2 ms) SELECT SUM("invoices"."total_cache") FROM "invoices" WHERE "invoices"."id" IN (SELECT "invoices"."id" FROM "invoices" INNER JOIN "projects" ON "projects"."id" = "invoices"."project_id" INNER JOIN "estimates" ON "estimates"."project_id" = "projects"."id" WHERE "estimates"."user_id" = $1)  [["user_id", 1]]
# => 5

最新更新