Я хочу ответить на этот вопрос с точки зрения ассоциации, ссылающейся на себя, а не только через has_many: через перспективу.
Допустим, у нас есть CRM с контактами. Контакты будут иметь отношения с другими контактами, но вместо того, чтобы создавать отношения между двумя разными моделями, мы будем создавать отношения между двумя экземплярами одной и той же модели. У контакта может быть много друзей, и он может быть подружен со многими другими контактами, поэтому нам придется создавать отношения многие-ко-многим.
Если мы используем RDBMS и ActiveRecord, мы бы использовали has_many: through. Таким образом, нам нужно будет создать модель соединения, такую как Дружба. В этой модели будет два поля: contact_id, представляющий текущего контакта, добавляющего друга, и friend_id, представляющего пользователя, с которым происходит дружба.
Но мы используем MongoDB и Mongoid. Как указано выше, Mongoid не имеет has_many: through или эквивалентной функции. Это не было бы так полезно с MongoDB, потому что он не поддерживает запросы соединения. Поэтому, чтобы смоделировать отношение многие-многие в базе данных, не являющейся СУБД, такой как 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
В чем разница между связанными контактами и контактами, имеющими много и принадлежащими ко многим практикам? Огромная разница! Одним из них является отношения между двумя сущностями. Другое - это ссылка на себя.