Schienen, die das Array von Objekten nach Attributwerten filtern

95

Also führe ich eine Abfrage an die Datenbank durch und habe ein vollständiges Array von Objekten:

@attachments = Job.find(1).attachments

Jetzt, wo ich ein Array von Objekten habe, möchte ich keine weitere Datenbankabfrage mehr ausführen, aber ich möchte das Array basierend auf den AttachmentObjekten filtern , file_typedamit ich eine Liste mit attachmentsdem Dateityp 'logo'und dann eine weitere Liste mit dem Objekttyp erhalten kannattachments wo Der Dateityp ist'image'

Etwas wie das:

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

Aber im Speicher statt einer Datenbankabfrage.

Joepour
quelle
Scheint ein guter Anwendungsfall für partition- Beispiel hier .
SRack

Antworten:

172

Versuchen :

Das ist in Ordnung :

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

In Bezug auf die Leistung müssen Sie @attachments jedoch nicht zweimal durchlaufen:

@logos , @images = [], []
@attachments.each do |attachment|
  @logos << attachment if attachment.file_type == 'logo'
  @images << attachment if attachment.file_type == 'image'
end
Vik
quelle
2
Da die Lösung von @ Vik ziemlich ideal ist, möchte ich nur hinzufügen, dass Sie in binären Fällen eine Partitionsfunktion verwenden können, um die Dinge süß zu machen. ruby-doc.org/core-1.9.3/Enumerable.html#method-i-partition
Vlad
Danke @Vlad, das ist cool, aber es wird nur unterstützt, wenn wir nur zwei Dinge vom Objekt sammeln müssen.
Vik
1
Ja, deshalb habe ich "binär" gesagt :). Bei der Frage gab es anscheinend eine Auswahl an Logo oder Bild, daher habe ich dies der Vollständigkeit halber hinzugefügt.
Vlad
8

Wenn Ihre Anhänge sind

@attachments = Job.find(1).attachments

Dies ist ein Array von Anhangsobjekten

Verwenden Sie die Auswahlmethode, um nach Dateityp zu filtern.

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

Dies löst keine Datenbankabfrage aus.

Soundar Rathinasamy
quelle
2

Haben Sie versucht, eifrig zu laden?

@attachments = Job.includes(:attachments).find(1).attachments
Siwei Shen 申思维
quelle
Es tut mir leid, dass mir nicht klar ist: Wie filtere ich nach dem Wert eines Objektattributs, ohne das Array zu durchlaufen?
Joepour
Wenn ich das richtig verstanden habe, möchten Sie weniger Datenbankabfragen, insbesondere wenn eine Abfrage wie @attachments = Job.first.attachmentsausgeführt ausgeführt wird, möchten Sie eine Schleife ausführen, während Sie @attachmentskeine weiteren Datenbankabfragen mehr wünschen. willst du das machen
Siwei Shen 申思维
Ich mache eine Datenbankabfrage und erhalte eine Reihe von Objekten. Ich möchte dann zwei separate Listen aus diesem einen Array erstellen, indem ich die Objekte basierend auf dem Wert ihrer Attribute
filtere
0

Sie können mit where filtern

Job.includes(:attachments).where(file_type: ["logo", "image"])
Darlan Dieterich
quelle
0

Ich würde das etwas anders machen. Strukturieren Sie Ihre Abfrage so, dass nur das abgerufen wird, was Sie benötigen, und teilen Sie sie von dort auf.

Stellen Sie Ihre Anfrage also wie folgt:

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

Und dann partitionieren Sie die Daten:

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

Dadurch erhalten Sie die gewünschten Daten auf übersichtliche und effiziente Weise.

SRack
quelle