Rel pemfilteran array objek berdasarkan nilai atribut


96

Jadi saya melakukan kueri ke db dan saya memiliki array objek yang lengkap:

@attachments = Job.find(1).attachments

Sekarang saya memiliki array objek, saya tidak ingin melakukan kueri db lagi, tetapi saya ingin memfilter array berdasarkan Attachmentobjek file_typesehingga saya dapat memiliki daftar di attachmentsmana jenis file itu 'logo'dan kemudian daftar lain di attachmentsmana jenis filenya adalah'image'

Sesuatu seperti ini:

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

Namun dalam memori, bukan kueri db.


Sepertinya kasus penggunaan yang baik partition- contohnya di sini .
SRack

Jawaban:


172

Coba:

Ini bagus:

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

tetapi untuk performa, Anda tidak perlu mengulang @attachments dua kali:

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

2
Karena solusi @ Vik cukup ideal, saya hanya akan menambahkannya dalam kasus biner, Anda dapat menggunakan fungsi 'partisi' untuk membuatnya lebih manis. ruby-doc.org/core-1.9.3/Enumerable.html#method-i-partition
Vlad

Terima kasih @Vlad, itu keren, tetapi hanya mendukung jika kita perlu mengumpulkan hanya dua hal dari objek.
Vik

1
Ya, itulah mengapa saya mengatakan "biner" :). Pada soal tersebut ternyata ada pilihan logo atau gambar, jadi saya tambahkan ini untuk kelengkapan.
Vlad

8

Jika keterikatan Anda

@attachments = Job.find(1).attachments

Ini akan menjadi array objek lampiran

Gunakan metode pilih untuk memfilter berdasarkan tipe_file.

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

Ini tidak akan memicu kueri db apa pun.


2

sudahkah Anda mencoba eager loading?

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

Maaf, saya kurang jelas: bagaimana cara memfilter menurut nilai atribut objek tanpa mengulang melalui array?
joepour

Jika saya mengerti dengan benar, Anda menginginkan lebih sedikit kueri db, terutama, setelah kueri seperti @attachments = Job.first.attachmentsdieksekusi, Anda ingin mengulang @attachmentssementara itu Anda tidak ingin kueri db lagi. apakah ini yang ingin kamu lakukan?
Siwei Shen 申思维

Saya melakukan kueri db dan menerima berbagai objek. Saya kemudian ingin membuat dua daftar terpisah dari satu array itu dengan memfilter objek berdasarkan nilai atributnya (Lihat posting asli) - cheers
joepour

0

Anda dapat memfilter menggunakan mana

Job.includes(:attachments).where(file_type: ["logo", "image"])

0

Saya akan melakukan ini sedikit berbeda. Susun kueri Anda untuk mengambil hanya yang Anda butuhkan dan pisahkan dari sana.

Jadi buat kueri Anda sebagai berikut:

#                                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"] })

Dan kemudian partisi data:

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

Itu akan mendapatkan data yang Anda cari dengan cara yang rapi dan efisien.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.