Quiero responder a esta pregunta desde la perspectiva de la asociación autorreferencial, no solo de has_many: a través de la perspectiva.
Digamos que tenemos un CRM con contactos. Los contactos tendrán relaciones con otros contactos, pero en lugar de crear una relación entre dos modelos diferentes, crearemos una relación entre dos instancias del mismo modelo. Un contacto puede tener muchos amigos y ser amigo de muchos otros contactos, por lo que tendremos que crear una relación de muchos a muchos.
Si usamos un RDBMS y ActiveRecord, usaríamos has_many: through. Por lo tanto, necesitaríamos crear un modelo de unión, como Friendship. Este modelo tendría dos campos, un contact_id que representa el contacto actual que está agregando un amigo y un friend_id que representa al usuario que se hace amigo.
Pero estamos usando MongoDB y Mongoid. Como se indicó anteriormente, Mongoid no tiene has_many: through o una función equivalente. No sería tan útil con MongoDB porque no admite consultas de combinación. Por lo tanto, para modelar una relación muchos-muchos en una base de datos que no es RDBMS como MongoDB, usa un campo que contiene una matriz de claves 'externas' en cada lado.
class Contact
include Mongoid::Document
has_and_belongs_to_many :practices
end
class Practice
include Mongoid::Document
has_and_belongs_to_many :contacts
end
Como dice la documentación:
Las relaciones de muchas a muchas en las que los documentos inversos se almacenan en una colección separada del documento base se definen utilizando la macro has_and_belongs_to_many de Mongoid. Esto exhibe un comportamiento similar al de Active Record con la excepción de que no se necesita una colección de combinaciones, los identificadores de claves foráneas se almacenan como matrices a ambos lados de la relación.
Al definir una relación de esta naturaleza, cada documento se almacena en su colección respectiva, y cada documento contiene una referencia de "clave externa" al otro en forma de matriz.
# the contact document
{
"_id" : ObjectId("4d3ed089fb60ab534684b7e9"),
"practice_ids" : [ ObjectId("4d3ed089fb60ab534684b7f2") ]
}
# the practice document
{
"_id" : ObjectId("4d3ed089fb60ab534684b7e9"),
"contact_ids" : [ ObjectId("4d3ed089fb60ab534684b7f2") ]
}
Ahora, para una Asociación de autorreferencia en MongoDB, tiene algunas opciones.
has_many :related_contacts, :class_name => 'Contact', :inverse_of => :parent_contact
belongs_to :parent_contact, :class_name => 'Contact', :inverse_of => :related_contacts
¿Cuál es la diferencia entre contactos relacionados y contactos que tienen muchos y pertenecen a muchas prácticas? ¡Gran diferencia! Uno es una relación entre dos entidades. Otro es una autorreferencia.