代码之家  ›  专栏  ›  技术社区  ›  TiggerToo

基于列平均值筛选的Rails作用域

  •  0
  • TiggerToo  · 技术社区  · 6 年前

    所以,我有一个餐厅模型,一个餐厅有很多评论,每个评论都有一个整数评级,1-5。我有一个功能,允许用户按最低评级筛选餐厅列表,但目前,它在筛选之前将它们全部获取,然后使用Ruby select语句来删除那些我不想要的餐厅。我想把这个转换成一个更干净的解决方案,让SQL进行过滤,但是我很难弄清楚如何在作用域中进行过滤。

    我有这个,但它给了我一个“滥用聚合函数AVG()”的错误:

    scope :min_rating, -> (rating) { joins(:reviews).where('AVG(reviews.rating) > ?', rating)  if rating}
    

    此作用域的正确语法是什么?

    1 回复  |  直到 6 年前
        1
  •  2
  •   matthewd    6 年前

    你需要 .group("restaurants.id") 或者类似于在计算平均值时告诉它要将哪些评论集合在一起,然后将其移动到 .having 条件(在该分组之后应用):

    scope :min_rating, -> (rating) { joins(:reviews).group("restaurants.id").having('AVG(reviews.rating) > ?', rating) if rating }
    

    然而,这是一个很好的例子,说明对数据进行非规范化可能是有意义的——添加 average_rating 列到 restaurants ,并在每次保存审阅时重新计算。与分组计算不同的是,可以对该列进行索引,并对其进行有效过滤——这需要在存储评论时付出更多努力;这是一种权衡。