[ruby-on-rails] ¿Cómo implementar has_many: a través de las relaciones con Mongoid y mongodb?


Answers

Solo para ampliar esto, aquí están los modelos extendidos con métodos que actúan de forma muy similar al has_many: a través de ActiveRecord al devolver un proxy de consulta en lugar de una matriz de registros:

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
Question

Usando este ejemplo modificado de las guías de Rails , ¿cómo se modela una asociación relacional "has_many: through" usando mongoid?

El desafío es que mongoid no es compatible con has_many: como lo hace 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



Quiero responder a esta pregunta desde la perspectiva de la asociación autorreferencial, no solo desde la perspectiva has_many: through.

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, así que vamos a tener que crear una relación de muchos a muchos.

Si estamos utilizando 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 con quien se hace amistad.

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 unión. Por lo tanto, para modelar una relación muchos-muchos en una base de datos no RDBMS como MongoDB, utiliza un campo que contiene una matriz de claves 'extranjeras' 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 muchos a muchos donde los documentos inversos se almacenan en una colección separada del documento base se definen usando la macro has_and_belongs_to_many de Mongoid. Esto muestra un comportamiento similar a Active Record con la excepción de que no se necesita una colección de unión, los ID de clave externa se almacenan como matrices en cualquier lado 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" a la otra en forma de una 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 autorreferenciada 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 y contactos relacionados que tienen muchos y que pertenecen a muchas prácticas? ¡Gran diferencia! Una es una relación entre dos entidades. Otro es una autorreferencia.




Related