按父对象分组注释,按最旧的注释排序父对象
我有对评论的对象。 作为定期电子邮件摘要的一部分,我想确定一段时间的注释,并首先按照最早的注释对象的顺序显示对象。
数据:
object_id comment_id 30 40 40 42 32 41 30 43 32 44
输出:
对象#30
- 评论40
- 评论43
对象#40
- 评论42
对象#32
- 评论41
- 评论44
我正在使用此代码将数据传输到一个中间数组 – 我试图使用.group_by(&:commentable_id)一次性获取所有数据,但数据没有以正确的顺序出现。
comments = account.comments.all( :conditions => ["comments.created_at > ?", 8.hours.ago], :order => "comments.created_at asc" ).map { |c| [c.commentable_id,c.id] } => [ [30,40], [40,42], [32,41], [30,43], [32,44] ]
如果我可以将数据转换为以下forms,我可以迭代数组来构建电子邮件内容……
[ [30,[40,43]], [40,[42]], [32,[41,44]] ]
但我想知道我是否比我需要的更难……任何建议?
(我使用的是Rails 2.3和Ruby ree-1.8.7)
您可以使用具有数组聚合的组来访问您正在查找的数组表单。
数组聚合大量依赖数据库。 MySQL是GROUP_CONCAT。 Postgres’是ARRAY_AGG。 Sqlite没有开箱即用,但我知道你可以定义自定义聚合函数,所以这不是不可能的。
实际上还没有尝试过运行这段代码,但是这里应该指向正确的方向:
result = Object.all( :select => 'objects.id, GROUP_CONCAT(comment_id) AS comment_array', :group => 'comments.id' ).map { |c| [c.id, c.comment_array] }
我使用了第一个示例中的命名,因此您需要将“对象”更改为您调用的表。 希望它有意义。 Rails可能没有内置的解析数组的支持,所以它可能会为comment_array返回一个字符串,你可能需要解析它。
在单个块/元素中拥有单个对象的所有注释肯定会使对它们进行任何操作时的生活更轻松。 但是,我不会把它们变成一个数组数组,因为它已经是一个数组数组。 我更喜欢像这样创建一个哈希:
comments_array = [ [30,40], [32,41], [40,42], [30,43], [32,44] ] obj_with_comments = {} comments_array.each do |x| obj_with_comments[x.first] ||= [] obj_with_comments[x.first] << x.last end obj_with_comments #=> {40=>[42], 30=>[40, 43], 32=>[41, 44]}
但是这提出了另一个问题,即哈希不是有序的,所以如果你只是迭代哈希,你会以一些随机的方式丢失你的顺序。 但是,您可以创建一个对象数组,然后迭代遍历哈希,如下所示:
objects = comments_array.collect{|x| x.first}.uniq objects #=> [30, 32, 40] # now get the hash value for each object key in order objects.each { |obj| puts obj_with_comments[obj].inspect }
希望有道理。
试试这个:
comments = account.comments.all( :conditions => ["comments.created_at > ?", 8.hours.ago], :order => "comments.commentable_id ASC, comments.id ASC" ).map { |c| [c.commentable_id,c.id] }
这将返回以下结果集:
=> [ [30,40], [30,43], [32,41], [32,44], [40,42] ]
在上面的查询中,我使用id进行排序而不是create_at
。 如果您正在使用MySQL并且如果id是自动生成的,则此逻辑将起作用,因为新对象的id
将高于旧对象的id
。 如果您不允许编辑注释,则此逻辑将起作用。
如果要按日期显式排序,请使用以下语法:
comments = account.comments.all( :joins => "accounts AS accounts ON comments.commentable_type = 'Account' AND comments.commentable_id = accounts.id", :conditions => ["comments.created_at > ?", 8.hours.ago], :order => "accounts.id ASC, comments.id ASC" ).map { |c| [c.commentable_id,c.id] }