Ruby on rails ';拆分';ActiveRecord集合

Ruby on rails ';拆分';ActiveRecord集合,ruby-on-rails,ruby,database,activerecord,Ruby On Rails,Ruby,Database,Activerecord,假设我有两个模型,分别是Post和Category: class Post < ActiveRecord::Base belongs_to :category end class Category < ActiveRecord::Base has_many :posts end 换句话说,按选定的类别ID将所有帖子的集合“拆分”为数组当然,但考虑到您的模型关系,我认为您需要从另一个角度来看待它 p = [] 1.upto(some_limit) do |n| post

假设我有两个模型,分别是Post和Category:

class Post < ActiveRecord::Base
  belongs_to :category
end

class Category < ActiveRecord::Base
  has_many :posts
end

换句话说,按选定的类别ID将所有帖子的集合“拆分”为数组当然,但考虑到您的模型关系,我认为您需要从另一个角度来看待它

p = []
1.upto(some_limit) do |n|
  posts = Category.posts.find_by_id(n)
  p.push posts if posts
end

类似的方法可能会起作用(Post的实例方法,未经测试):

def按类别拆分(*id)
自注入([])do | arr,p|
arr[p.category_id]| |=[]

arr[p.category\u id]在
Array
类上尝试
group\u by
功能:

posts.group_by(&:category_id)
有关更多详细信息,请参阅API

注意事项:

当潜在数据集可能很大时,不应在Ruby代码中执行分组。当最大可能的数据集大小<1000时,我使用
groupby
函数。在您的情况下,您可能有1000个
Post
s。处理这样一个数组会给您的资源带来压力。依靠数据库执行分组/排序/聚合等

下面是一种方法(类似的解决方案由
nas
建议)


与其获取所有帖子,然后对它们进行一些操作以对它们进行分类,这是一个性能密集型的练习,我更愿意像这样使用即时加载

categories = Category.all(:include => :posts)
这将生成一个sql查询来获取所有文章和类别对象。然后,您可以轻松地对其进行迭代:

p = Array.new
categories.each do |category| 
  p[1] = category.posts
  # do anything with p[1] array of posts for the category
end

是的,但这样它将运行一些限制SQL查询,如果可能的话,我只想使用一个查询(posts=Post.find(:all))。@nas这将返回没有posts的类别。你必须添加额外的条件来过滤没有帖子的类别。@Kandaboggu我认为你是否得到没有帖子的类别并不重要,因为根据问题@Vincent正在对帖子而不是类别进行操作。当您调用
category.posts
时,您将得到一个空数组,在空数组中迭代不会执行代码块,因此没有效果。因此,根据场景,这里不需要任何条件。因为帖子有类别,@Vincent的逻辑不必处理没有帖子的类别场景。最好通过添加附加条件在DB级别过滤掉空类别。@Kandaboggu对不起,帖子没有类别;类别有职位,职位属于类别。为什么你认为@Vincent的逻辑必须处理没有帖子的类别场景?请你再看一次我之前的评论好吗?
posts
表中有一列名为
category\u id
。每个帖子都有一个类别,一个类别可能有帖子,也可能没有帖子。我的观点是消除DB查询中的空类别,而不是ruby代码中的空类别。这将减少SQL返回的categories结果集大小,并加快延迟获取查询的速度。“group_by”解决方案正是我想要的,谢谢!
# returns the categories with at least one post
# the posts associated with the category are pre-fetched
Category.all(:include => :posts, 
    :conditions => "posts.id IS NOT NULL").each do |cat| 
  cat.posts
end
categories = Category.all(:include => :posts)
p = Array.new
categories.each do |category| 
  p[1] = category.posts
  # do anything with p[1] array of posts for the category
end