Korzystając z tego zmodyfikowanego przykładu z przewodników Railsów , w jaki sposób można modelować relacyjne powiązanie „has_many:” za pomocą „mongoid”?
Wyzwanie polega na tym, że mongoid nie obsługuje has_many: through, tak jak robi to ActiveRecord.
# doctor checking out patient
class Physician < ActiveRecord::Base
has_many :appointments
has_many :patients, :through => :appointments
has_many :meeting_notes, :through => :appointments
end
# notes taken during the appointment
class MeetingNote < ActiveRecord::Base
has_many :appointments
has_many :patients, :through => :appointments
has_many :physicians, :through => :appointments
end
# the patient
class Patient < ActiveRecord::Base
has_many :appointments
has_many :physicians, :through => :appointments
has_many :meeting_notes, :through => :appointments
end
# the appointment
class Appointment < ActiveRecord::Base
belongs_to :physician
belongs_to :patient
belongs_to :meeting_note
# has timestamp attribute
end
źródło
Aby to rozwinąć, oto modele rozszerzone o metody, które działają bardzo podobnie do has_many: poprzez z ActiveRecord, zwracając proxy zapytania zamiast tablicy rekordów:
class Physician include Mongoid::Document has_many :appointments def patients Patient.in(id: appointments.pluck(:patient_id)) end end class Appointment include Mongoid::Document belongs_to :physician belongs_to :patient end class Patient include Mongoid::Document has_many :appointments def physicians Physician.in(id: appointments.pluck(:physician_id)) end end
źródło
.pluck()
sinstead.map
jest DUŻO szybsze. Czy możesz zaktualizować swoją odpowiedź dla przyszłych czytelników?undefined method 'pluck' for #<Array:...>
Rozwiązanie Stevena Soroki jest naprawdę świetne! Nie mam reputacji, by komentować odpowiedź (dlatego dodaję nową odpowiedź: P), ale myślę, że używanie mapy do związku jest kosztowne (szczególnie jeśli twój związek has_many ma setki | tysiące rekordów), ponieważ dane z bazy danych, buduj każdy rekord, generuje oryginalną tablicę, a następnie wykonuje iterację po oryginalnej tablicy, aby zbudować nową z wartościami z danego bloku.
Używanie skubania jest szybsze i być może najszybszą opcją.
class Physician include Mongoid::Document has_many :appointments def patients Patient.in(id: appointments.pluck(:patient_id)) end end class Appointment include Mongoid::Document belongs_to :physician belongs_to :patient end class Patient include Mongoid::Document has_many :appointments def physicians Physician.in(id: appointments.pluck(:physician_id)) end end
Oto kilka statystyk z Benchmark.measure:
> Benchmark.measure { physician.appointments.map(&:patient_id) } => #<Benchmark::Tms:0xb671654 @label="", @real=0.114643818, @cstime=0.0, @cutime=0.0, @stime=0.010000000000000009, @utime=0.06999999999999984, @total=0.07999999999999985> > Benchmark.measure { physician.appointments.pluck(:patient_id) } => #<Benchmark::Tms:0xb6f4054 @label="", @real=0.033517774, @cstime=0.0, @cutime=0.0, @stime=0.0, @utime=0.0, @total=0.0>
Korzystam tylko z 250 spotkań. Nie zapomnij dodać indeksów do: patient_id i: physician_id w dokumencie spotkania!
Mam nadzieję, że to pomoże. Dziękuję za przeczytanie!
źródło
undefined method 'pluck' for #<Array:...>
Chcę odpowiedzieć na to pytanie z perspektywy asocjacji odnoszących się do samych siebie, a nie tylko z perspektywy has_many: poprzez perspektywę.
Powiedzmy, że mamy CRM z kontaktami. Kontakty będą miały relacje z innymi kontaktami, ale zamiast tworzyć relacje między dwoma różnymi modelami, utworzymy relację między dwoma wystąpieniami tego samego modelu. Kontakt może mieć wielu przyjaciół i być zaprzyjaźniony z wieloma innymi kontaktami, więc będziemy musieli stworzyć relację wiele do wielu.
Jeśli używamy RDBMS i ActiveRecord, użylibyśmy has_many: through. Dlatego musielibyśmy stworzyć model łączenia, taki jak Przyjaźń. Ten model miałby dwa pola, contact_id, które reprezentuje bieżący kontakt, który dodaje znajomego, oraz friend_id, który reprezentuje zaprzyjaźnionego użytkownika.
Ale używamy MongoDB i Mongoid. Jak wspomniano powyżej, Mongoid nie ma funkcji has_many: through ani równoważnej funkcji. Nie byłoby to tak przydatne w MongoDB, ponieważ nie obsługuje zapytań łączących. Dlatego w celu modelowania relacji wiele-wiele w bazie danych innej niż RDBMS, takiej jak MongoDB, należy użyć pola zawierającego tablicę kluczy „obcych” po obu stronach.
class Contact include Mongoid::Document has_and_belongs_to_many :practices end class Practice include Mongoid::Document has_and_belongs_to_many :contacts end
Jak podaje dokumentacja:
# the contact document { "_id" : ObjectId("4d3ed089fb60ab534684b7e9"), "practice_ids" : [ ObjectId("4d3ed089fb60ab534684b7f2") ] } # the practice document { "_id" : ObjectId("4d3ed089fb60ab534684b7e9"), "contact_ids" : [ ObjectId("4d3ed089fb60ab534684b7f2") ] }
Teraz, jeśli chodzi o stowarzyszenie odwołujące się do siebie w MongoDB, masz kilka opcji.
has_many :related_contacts, :class_name => 'Contact', :inverse_of => :parent_contact belongs_to :parent_contact, :class_name => 'Contact', :inverse_of => :related_contacts
Jaka jest różnica między kontaktami pokrewnymi a kontaktami, które mają wiele i należą do wielu praktyk? Duża różnica! Jedna to relacja między dwoma podmiotami. Inny to odniesienie do samego siebie.
źródło