【问题标题】:Get last comment of all posts in one category获取一个类别中所有帖子的最后评论
【发布时间】:2014-11-20 21:39:04
【问题描述】:

评论属于帖子。
帖子属于类别。

我如何获得每篇文章最后更新的评论的集合,所有评论都属于一个类别?

我试过了,但它只给了我一个帖子:

category.posts.joins(:comments).order('updated_at DESC').first

更新

我想要的是为每个帖子获取一个评论,即每个帖子的最后更新评论。

【问题讨论】:

  • 您使用的是什么数据库? Rails 不能很好地支持这一点,所以我们需要去一个较低的级别让它很好地工作。
  • 我正在使用 PostgreSQL。

标签: ruby-on-rails postgresql ruby-on-rails-4 rails-activerecord postgresql-9.3


【解决方案1】:

Rails 在这方面做得不是特别好,尤其是 Postgres,它禁止明显的解决方案(由 @Jon 和 @Deefour 给出)。

这是我使用的解决方案,已翻译为您的示例域:

class Comment < ActiveRecord::Base
  scope :most_recent, -> { joins(
    "INNER JOIN (
      SELECT DISTINCT ON (post_id) post_id,id FROM comments ORDER BY post_id,updated_at DESC,id
    ) most_recent ON (most_recent.id=comments.id)"
  )}
  ...

DISTINCT ON 是对 SQL 标准的 Postgres 扩展,因此它不适用于其他数据库。)

简要说明:DISTINCT ON 删除除每个 post_id 的第一行之外的所有行。它通过使用ORDER BY 来决定第一行是哪一行,它必须以post_id 开头,然后按updated at DESC 排序以获取最新的,然后将id 作为决胜局(通常不需要)。

然后你会这样使用它:

Comment.most_recent.joins(:post).where("posts.category_id" => category.id)

它生成的查询类似于:

SELECT *
FROM comments
  INNER JOIN posts ON (posts.id=comments.post_id)
  INNER JOIN (
    SELECT DISTINCT ON (post_id) post_id,id FROM comments ORDER BY post_id,updated_at DESC,id
  ) most_recent ON (most_recent.id=comments.id)
WHERE
  posts.category_id=#{category.id}

单一查询,相当高效。如果有人能给我一个不那么复杂的解决方案,我会欣喜若狂!

【讨论】:

    【解决方案2】:

    如果您想要收集每个最后更新的评论,您需要将查询基于Comment,而不是Category

    Comment.joins(:post).
            where("posts.category_id = ?", category.id).
            group("posts.id").
            order("comments.updated_at desc")
    

    【讨论】:

      【解决方案3】:

      您基本上要求的是has_many :through 关联。

      尝试像这样设置您的 Category 模型:

      class Category < ActiveRecord::Base
        has_many :posts
        has_many :comments, through: :posts
      end
      

      然后您可以简单地执行此操作来获取最近 10 个更新的 cmets:

      category.comments.order('updated_at DESC').limit(10)
      

      您可以在 Comment 模型上使用命名范围使其更具可读性:

      class Comment < ActiveRecord::Base
        scope :recently_updated, -> { order('updated_at DESC').limit(10) }
      end
      

      为您提供此查询以用于获取相同的 10 cmets:

      category.comments.recently_updated
      

      编辑

      因此,对于您真正想要的问题,一个类似的解决方案,但是它要求您从 Comment 结束事情来处理您的关联。

      首先,在Comment上建立一个关联,让它知道自己的Category

      class Comment < ActiveRecord::Base
        belongs_to :post
        has_one :category, through: :post
      end
      

      现在您可以像这样查询您的 cmets:

      Comment.order('updated_at desc').joins(:post).where('posts.category' => category).group(:post_id)
      

      有点啰嗦,但确实有效。

      【讨论】:

      • 这种结构是否可以为每个帖子获得一条评论(最后更新)? (对不起,如果我对此不够清楚。)
      • 你是对的——你真的不是很清楚。我会更新我的答案。
      • @Jon SQL group by 返回聚合而不是表的行。不幸的是,真正的解决方案比.order.group复杂得多。
      • 是的——我的错。在这种情况下,您可能无法避免从Comment 开始的查询混乱。
      • 那应该更好。
      【解决方案4】:

      .first 只为你抓取一个。确切地说是第一个。所以放弃.first。所以改为:

      category.posts.joins(:comments).order('updated_at DESC')

      【讨论】:

      • 这只是返回所有帖子.. :/
      • 对不起。我误解了你。我刚刚对上面的正确答案投了赞成票。
      猜你喜欢
      • 2015-10-14
      • 2014-08-14
      • 2017-07-26
      • 2015-04-17
      • 2012-04-12
      • 2018-08-16
      • 2014-01-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多