2

我相信这是一个简单的红宝石问题。在我的应用程序中,我有具有多个评论的产品模型。每个评论都有一个“整体”评级的属性,它是一个整数。

我想做的是根据总体评分的平均值显示前十名产品。我已经让这个工作了,但是,我还想通过二级聚合属性对具有相同总体评级的产品进行排序,这将是该产品有多少评论。现在,如果我有 3 个具有相同平均总体评分的产品,它们似乎以随机顺序显示。

到目前为止,我的代码是:

控制器

@best = Product.has_reviews.get_best_products(10)

产品型号

scope :has_reviews, joins{reviews.outer}.where{reviews.id != nil}

def self.get_best_products(number)
  sorted = self.uniq
  sorted = sorted.sort { |x, y| y.reviews.average("overall").to_f <=> x.reviews.average("overall").to_f }
  sorted.first(number)
end

我已经为我的模型代码尝试了这个:

def self.get_best_products(number)
  sorted = self.uniq.sort! { |x, y| x.reviews.count.to_f <=> y.reviews.count.to_f }
  sorted = sorted.sort { |x, y| y.reviews.average("overall").to_f <=> x.reviews.average("overall").to_f }
  sorted.first(number)
end

...但它没有做我想做的事。我只是在我的视图中使用 each 遍历 @best 数组。

- -更新

好的,现在我正在尝试这个:

控制器:

@best = Product.get_best_products(6)

模型:

def self.get_best_products(number)
  self.joins{reviews}.order{'AVG(reviews.overall), COUNT(reviews)'}.limit(number)
end

但我收到此错误:

PGError: ERROR:  column "products.id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT  "products".* FROM "products" INNER JOIN "reviews" ...

我正在使用 Squeel gem btw 来避免在模型中有直接的 SQL 代码。

----更新2

现在我将“组”部分添加到我的方法中,但仍然出现错误:

def self.get_best_products(number)
  self.joins{reviews}.group('product.id').order{'AVG(reviews.overall), COUNT(reviews)'}.limit(number)
end

我收到此错误:

PGError: ERROR:  missing FROM-clause entry for table "product"
LINE 1: ...eviews"."product_id" = "products"."id" GROUP BY product.i...
4

2 回答 2

0

产品.rb

scope :best_products, (lambda do |number|
  joins(:reviews).order('AVG(reviews.overall), COUNT(reviews)').limit(number)
)

products_controller.rb

Product.best_products(10)

这可以确保一切都发生在数据库中,因此您不会获得不需要的记录。

于 2013-06-23T15:26:21.427 回答
0

如果我做对了,这就是我的想法:

由于products有很多reviews并且reviews有一个overall属性,我会reviews_counter在 products 表中添加一个列,该列将随着每次添加的评论而增加,这样您就可以获得更多的数据库性能,因为您不必获得count所有products评论评论最多的一个。

现在您将获得按以下顺序订购的产品reviews_counter

@best_products = Products.order("reviews_counter desc")

接下来,您将获得按reviews以下顺序订购的每种产品overall

<% for prod in @best_products %>
  <%= prod.reviews.order("overall desc") %> # can do all this or more in helper
<% end %>

同样以这种方式排序,如果您有 3 条总体相同的评论,您可以再添加一条order()语句并按nameid或您喜欢的任何方式对其进行排序,这样它们就不会以随机顺序显示。

这只是我的想法,我最近在一个需要类似的应用程序上工作,我们只是在我们的模型中添加了一个 counter_field,这样做并不违法 :)

ps 对我来说不是很清楚您希望为每个记录显示多少条记录,因此您只需要添加.limit(5)例如仅获得产品的前 5 条评论。

于 2013-06-23T18:38:32.887 回答