Rails(Activerecord)-如果没有重复项,则无法使用联接和全局和进行查询

时间:2019-01-31 13:36:30

标签: ruby-on-rails postgresql activerecord

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

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

此外,我使用Rails的汇总方法“ sum”来找出发票的总额@ invoices.sum(:total_cache),其中total_cache是​​数据库中专门设计用于执行此类的缓存列以一种高性能的方式计算总和。

@invoices.sum(:total_cache)

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

过滤的行为很好,因为我的意图是对在发票项目中进行任何估算的用户进行过滤。但是,问题是,当我尝试通过添加组('invoices.id')来避免重复时(这是我始终解决此类情况的方式),最终的求和操作不会返回发票总额的总和。 ,但是它们每个的分组总和(完全没用)。

我发现的唯一解决方法是包括group子句,并在纯红宝石代码中执行总和,将集合视为数组,恕我直言,这是非常低效的,因为有大量的发票:

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

是否可以通过一种方法来获取唯一的ActiveRecord发票集合(没有重复项),然后再调用汇总和方法并获得Postgres计算出的总额?

当然,如果我的基本想法有问题,我完全乐意听到!这是一个非常复杂的查询(为方便起见,我在此简化了查询),而且我可以肯定有很多方法!

谢谢大家!

1 个答案:

答案 0 :(得分:2)

我不确定这比“红宝石”代码中的总和要“慢”或“快”多少。但是,如果您仍然想保留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