Rails按属性值过滤对象数组


95

因此,我对数据库执行查询,并且有完整的对象数组:

@attachments = Job.find(1).attachments

现在,我有对象,我不想执行另一个数据库查询的数组,但我想基于对数组筛选Attachment对象的file_type,这样我可以有一个列表attachments,其中文件类型为'logo',然后另一个列表attachments哪里文件类型是'image'

像这样:

@logos  = @attachments.where("file_type = ?", 'logo')
@images = @attachments.where("file_type = ?", 'image')

但是在内存而不是数据库查询中。


似乎是一个很好的使用情况partition- 例如这里
SRack,

Answers:


172

尝试:

这可以 :

@logos = @attachments.select { |attachment| attachment.file_type == 'logo' }
@images = @attachments.select { |attachment| attachment.file_type == 'image' }

但是出于性能考虑,您不需要重复两次@attachments:

@logos , @images = [], []
@attachments.each do |attachment|
  @logos << attachment if attachment.file_type == 'logo'
  @images << attachment if attachment.file_type == 'image'
end

2
由于@Vik的解决方案非常理想,因此我将在二进制情况下添加它,您可以使用“分区”函数使事情变得甜蜜。 ruby-doc.org/core-1.9.3/Enumerable.html#method-i-partition
Vlad

感谢@Vlad,这很酷,但是仅当我们只需要从对象中收集两件事时,它才支持。
维克

1
是的,这就是为什么我说“ binary” :)。在问题中,显然可以选择徽标或图像,因此为了完整性起见,我添加了此选项。
弗拉德

8

如果您的附件是

@attachments = Job.find(1).attachments

这将是附件对象的数组

使用select方法基于file_type进行过滤。

@logos = @attachments.select { |attachment| attachment.file_type == 'logo' }
@images = @attachments.select { |attachment| attachment.file_type == 'image' }

这不会触发任何数据库查询。


2

您是否尝试过快速加载?

@attachments = Job.includes(:attachments).find(1).attachments

抱歉,我不清楚:如何在不循环遍历数组的情况下按对象属性的值进行过滤?
12

如果我理解正确,则希望减少数据库查询,尤其是一旦@attachments = Job.first.attachments执行了查询之类的查询后,就想循环,@attachments而又不想再进行任何数据库查询。这是你想做的吗?
沉思玮申思思维

我执行数据库查询并接收对象数组。然后,我想根据该对象的属性值过滤对象,从而从该数组中创建两个单独的列表(请参阅原始帖子)-干杯
joepour 2012年


0

我会略有不同。结构化查询以仅检索所需内容并从中进行拆分。

因此,请执行以下查询:

#                                vv or Job.find(1) vv
attachments = Attachment.where(job_id: @job.id, file_type: ["logo", "image"])
# or 
Job.includes(:attachments).where(id: your_job_id, attachments: { file_type: ["logo", "image"] })

然后对数据进行分区:

@logos, @images = attachments.partition { |attachment| attachment.file_type == "logo" }

这将以一种整齐而高效的方式获取您所需要的数据。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.