Я хочу відповісти на це питання з точки зору асоціації, що посилається на себе, а не лише з has_many: через перспективу.
Скажімо, у нас є CRM з контактами. Контакти матимуть зв’язки з іншими контактами, але замість того, щоб створювати зв’язок між двома різними моделями, ми створимо зв’язок між двома екземплярами однієї моделі. У контакту може бути багато друзів і дружити з багатьма іншими контактами, тому нам доведеться створити стосунки багато-до-багатьох.
Якщо ми використовуємо СУБД та ActiveRecord, ми б використовували has_many: through. Таким чином, нам потрібно було б створити модель об’єднання, як Дружба. Ця модель мала б два поля: contact_id, який представляє поточний контакт, який додає друга, і friend_id, який представляє користувача, з яким дружимо.
Але ми використовуємо MongoDB та Mongoid. Як зазначено вище, Mongoid не має has_many: through або еквівалентної функції. Це не було б настільки корисним для MongoDB, оскільки він не підтримує запити на приєднання. Отже, для того, щоб змоделювати взаємозв'язок багато-багато в базі даних, що не є RDBMS, наприклад MongoDB, ви використовуєте поле, що містить масив `` зовнішніх '' ключів з обох сторін.
class Contact
include Mongoid::Document
has_and_belongs_to_many :practices
end
class Practice
include Mongoid::Document
has_and_belongs_to_many :contacts
end
Як зазначено в документації:
Багато-багато взаємозв'язків, де зворотні документи зберігаються в окремій колекції від базового документа, визначаються за допомогою макросу Mongoid has_and_belongs_to_many. Це демонструє подібну поведінку до Active Record, за винятком того, що не потрібна колекція об’єднань, ідентифікатори зовнішнього ключа зберігаються як масиви по обидві сторони відношення.
При визначенні відношення такого характеру кожен документ зберігається у відповідній колекції, і кожен документ містить посилання на “зовнішній ключ” на інший у вигляді масиву.
# the contact document
{
"_id" : ObjectId("4d3ed089fb60ab534684b7e9"),
"practice_ids" : [ ObjectId("4d3ed089fb60ab534684b7f2") ]
}
# the practice document
{
"_id" : ObjectId("4d3ed089fb60ab534684b7e9"),
"contact_ids" : [ ObjectId("4d3ed089fb60ab534684b7f2") ]
}
Тепер для асоціації, що посилається на себе в MongoDB, у вас є кілька варіантів.
has_many :related_contacts, :class_name => 'Contact', :inverse_of => :parent_contact
belongs_to :parent_contact, :class_name => 'Contact', :inverse_of => :related_contacts
Яка різниця між пов’язаними контактами та контактами, які мають багато людей, і належать до багатьох практик? Величезна різниця! Один - це відносини між двома сутностями. Інше - це самореференція.