Rails กรองอาร์เรย์ของวัตถุตามค่าแอตทริบิวต์


98

ดังนั้นฉันจึงทำการค้นหาไปยังฐานข้อมูลและฉันมีอาร์เรย์ของวัตถุทั้งหมด:

@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

คำตอบ:


174

ลอง :

นี่เป็นเรื่องปกติ:

@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 เจ๋งดี แต่รองรับเฉพาะในกรณีที่เราต้องการรวบรวมเพียงสองสิ่งจากวัตถุ
Vik

1
ใช่นั่นคือเหตุผลที่ฉันพูดว่า "ไบนารี" :) ในคำถามเห็นได้ชัดว่ามีโลโก้หรือรูปภาพให้เลือกดังนั้นฉันจึงเพิ่มสิ่งนี้เพื่อความสมบูรณ์
Vlad

8

หากไฟล์แนบของคุณคือ

@attachments = Job.find(1).attachments

นี่คืออาร์เรย์ของวัตถุที่แนบมา

ใช้วิธีการเลือกเพื่อกรองตาม 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

ขออภัยฉันไม่ชัดเจน: ฉันจะกรองตามค่าของแอตทริบิวต์ออบเจ็กต์โดยไม่วนซ้ำอาร์เรย์ได้อย่างไร
joepour

ถ้าฉันเข้าใจถูกต้องคุณต้องการแบบสอบถาม db น้อยลงโดยเฉพาะอย่างยิ่งเมื่อการสืบค้นเช่น@attachments = Job.first.attachmentsดำเนินการแล้วคุณต้องการวนซ้ำใน@attachmentsขณะที่คุณไม่ต้องการแบบสอบถาม db อีก นี่คือสิ่งที่คุณต้องการทำหรือไม่?
Siwei Shen 申思维

ฉันทำแบบสอบถามฐานข้อมูลและรับอาร์เรย์ของวัตถุ จากนั้นฉันต้องการสร้างสองรายการที่แยกจากกันจากอาร์เรย์หนึ่งโดยการกรองวัตถุตามค่าของแอตทริบิวต์ (ดูโพสต์ต้นฉบับ) - ไชโย
joepour


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" }

ซึ่งจะได้รับข้อมูลที่คุณต้องการอย่างเรียบร้อยและมีประสิทธิภาพ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.