【问题标题】:How to sort through an associated attribute on two levels at once?如何一次对两个级别的关联属性进行排序?
【发布时间】:2013-06-23 14:37:58
【问题描述】:

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

我想做的是根据总体评分的平均值显示前十名产品。我已经让这个工作了,但是,我还想通过二级聚合属性对具有相同总体评级的产品进行排序,这将是该产品有多少评论。现在,如果我有 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 以避免在模型中直接使用 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...

【问题讨论】:

  • 在数据库中进行排序不是更好吗? IE。使用order 而不是sort
  • 应该是products.id 而不是product.id。我的错。

标签: ruby-on-rails


【解决方案1】:

product.rb

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

products_controller.rb

Product.best_products(10)

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

【讨论】:

  • 您好,感谢您的回答。我尝试逐字执行它,以及我在更新我的问题时执行它的方式。两种方式都产生了相同的错误。我尝试做 joins{reviews.outer} 但它也没有解决问题。你能告诉我出了什么问题吗?
  • 尝试添加.group('product.id')
  • 如果你要使用group,你也必须使用select
  • 你能给我举个例子来说明如何使用group和select一起吗?
【解决方案2】:

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

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

现在您将获得reviews_counter订购的产品:

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

接下来您将获得reviewsoverall 订购的每个产品的@:

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

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

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

附言我不清楚您希望为每条记录显示多少条记录,因此您只需添加 .limit(5) 即可,例如仅获得产品的前 5 条评论。

【讨论】:

  • 但是如果我像这样对控制器代码添加一个限制,我不会只按评论计数获得前 n 个产品,然后按整体对视图中的 n 条记录数组进行排序评分?如果我想优先考虑总体评分,然后仅按评论数量对总体平均评分相同的产品进行排序,该怎么办?
  • 对了,现在问题对我来说更清楚了,我会考虑一下,如果可以的话会更新它
  • 谢谢,感谢您的帮助
猜你喜欢
  • 1970-01-01
  • 2021-09-17
  • 2015-05-06
  • 1970-01-01
  • 2011-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多