2008-09-17 24 views
6

Ich habe eine zwei Tabellen mit einer Join-Tabelle verbunden - das ist nur Pseudo-Code:Rubin/Rails-Sammlung Sammlung

Library 
Book 
LibraryBooks 

Was ich brauche ist zu tun, wenn ich die ID eine Bibliothek haben, ich will um alle Bibliotheken zu erhalten, die alle Bücher dieser Bibliothek enthalten.

Also, wenn ich Bibliothek 1 habe, und Bibliothek 1 Bücher A und B in ihnen hat, und Bücher A und B in Bibliotheken 1, 2, und 3, gibt es eine elegante (eine Linie) Art und Weise dies in Schienen?

Ich dachte:

l = Library.find(1) 
allLibraries = l.books.libraries 

Aber das scheint nicht zu funktionieren. Vorschläge?

+0

Sie wollen also alle Bibliotheken, die Bücher haben? Das obige Code-Snippet würde nicht einfach die gleiche Bibliothek wie ich zurückgeben. Es ist so, als ob du all deine Bücher fragst, wer ihr Besitzer ist. Ein bisschen Verwirrung ... aber Jim's unten wird den Kollationstrick machen. – Gishu

+0

Alle Bibliotheken, die Bücher haben, die auch in dieser Bibliothek sind, ja? –

+0

@Jim - das ist genau das, was ich will – aronchick

Antwort

7
l = Library.find(:all, :include => :books) 
l.books.map { |b| b.library_ids }.flatten.uniq 

Beachten Sie, dass map(&:library_ids) langsamer als map { |b| b.library_ids } in Ruby 1.8.6 und schneller in 1.9.0.

Ich sollte auch erwähnen, dass, wenn Sie :joins anstelle von include dort verwendet würde, würde es die Bibliothek und verwandte Bücher alle in derselben Abfrage finden, die Datenbankzeit zu beschleunigen. :joins funktioniert jedoch nur, wenn eine Bibliothek Bücher hat.

+0

Die Langsamkeit von Symbol # to_proc wird normalerweise durch die Datenbankaufrufe aufgewogen. –

+0

Ich sehe nicht, wie das funktionieren könnte. Die erste Zeile gibt ein Array von Bibliotheksobjekten zurück (eigentlich ein Proxy, aber mit denselben Methoden). Dieses Array wird keine "Bücher" -Methode haben, so dass Zeile zwei fehlschlägt, oder? – MiniQuark

3

Vielleicht:

l.books.map {|b| b.libraries} 

oder

l.books.map {|b| b.libraries}.flatten.uniq 

, wenn Sie alles in einem flachen Array wollen.

Natürlich sollten Sie dies wirklich als eine Methode auf Bibliothek definieren, um die edle Ursache der Kapselung aufrecht zu erhalten.

2

Wenn Sie möchten, dass ein eindimensionales Array von Bibliotheken zurückgegeben wird, wobei Duplikate entfernt wurden.

l.books.map{|b| b.libraries}.flatten.uniq 
2

Ein Problem mit

l.books.map{|b| b.libraries}.flatten.uniq 

ist, dass es einen SQL-Aufruf für jedes Buch in l generieren. Ein besserer Ansatz (vorausgesetzt, ich verstehe Ihr Schema) könnte sein:

LibraryBook.find(:all, :conditions => ['book_id IN (?)', l.book_ids]).map(&:library_id).uniq 
+0

Dies ist nicht streng richtig, je nachdem, was ursprünglich geladen wurde. –

+0

Entschuldigung, ich hätte das klarstellen sollen: Ich gehe davon aus, dass Sie nichts anderes als l vorinstalliert haben (die ursprüngliche Bibliothek) –

+0

oops ... nicht sicher, dass das funktioniert ... meinst du LibraryBook oder Library? – aronchick

Verwandte Themen