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:
Wiele do wielu relacji, w których odwrotne dokumenty są przechowywane w oddzielnej kolekcji od dokumentu podstawowego, jest definiowanych za pomocą makra has_and_belongs_to_many Mongoida. Zachowuje się to podobnie jak w module Active Record, z wyjątkiem tego, że nie jest potrzebna żadna kolekcja złączeń, identyfikatory kluczy obcych są przechowywane jako tablice po obu stronach relacji.
Podczas definiowania relacji tego rodzaju, każdy dokument jest przechowywany w swojej odpowiedniej kolekcji, a każdy dokument zawiera odniesienie do innego „klucza obcego” w postaci tablicy.
# 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.