source

has_many : Mongoid 및 mongodb와의 관계를 통해 어떻게 구현합니까?

ittop 2023. 3. 28. 22:37
반응형

has_many : Mongoid 및 mongodb와의 관계를 통해 어떻게 구현합니까?

레일즈 가이드의 이 수정된 예를 사용하여 mongoid를 사용하여 관계형 "has_many:through" 연관성을 모델링하려면 어떻게 해야 합니까?

문제는 mongoid가 Active Record와 달리 has_many : 를 지원하지 않는다는 것입니다.

# 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

Mongoid에는 has_many : through 등의 기능이 없습니다.MongoDB에서는 Join 쿼리를 지원하지 않기 때문에 MongoDB에서는 그다지 유용하지 않습니다.따라서 관련된 컬렉션을 다른 것을 통해 참조할 수 있어도 여러 개의 쿼리가 필요합니다.

https://github.com/mongoid/mongoid/issues/544

일반적으로 RDBMS에서 다다 관계가 있는 경우 양쪽에 '외부' 키 배열을 포함하는 필드를 사용하여 MongoDB에서 다르게 모델링합니다.예를 들어 다음과 같습니다.

class Physician
  include Mongoid::Document
  has_and_belongs_to_many :patients
end

class Patient
  include Mongoid::Document
  has_and_belongs_to_many :physicians
end

즉, Join 테이블을 삭제하면 has_many : through와 같은 효과를 얻을 수 있습니다.그러나 당신의 경우 가입 테이블은 연관성뿐만 아니라 몇 가지 추가 정보를 포함하는 약속 클래스이기 때문에 적절하지 않을 수 있습니다.

이를 모델링하는 방법은 실행해야 하는 쿼리에 따라 어느 정도 다르지만 다음과 같이 예약 모델을 추가하고 환자 및 의사에게 연결을 정의해야 할 것으로 보입니다.

class Physician
  include Mongoid::Document
  has_many :appointments
end

class Appointment
  include Mongoid::Document
  belongs_to :physician
  belongs_to :patient
end

class Patient
  include Mongoid::Document
  has_many :appointments
end

MongoDB의 관계에서는 항상 임베디드 문서와 관련 문서 중 하나를 선택해야 합니다.귀하의 모델에서는 MeetingNotes가 임베디드 관계에 적합한 후보라고 생각합니다.

class Appointment
  include Mongoid::Document
  embeds_many :meeting_notes
end

class MeetingNote
  include Mongoid::Document
  embedded_in :appointment
end

즉, 약속과 함께 메모를 검색할 수 있지만, 이것이 연결일 경우 여러 개의 쿼리가 필요합니다.회의 노트가 매우 많은 경우 재생될 수 있는 단일 문서에 대한 16MB 크기 제한을 염두에 두면 됩니다.

확장하면 레코드 배열 대신 쿼리 프록시를 반환함으로써 ActiveRecord에서has_many :와 매우 유사한 방식으로 확장된 모델을 다음에 제시하겠습니다.

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

Steven Soroka 솔루션은 정말 훌륭합니다!답변에 대해 코멘트를 할 수 있는 평판은 없지만(그래서 새로운 답변을 추가하려고 합니다.P), 관계에서 지도를 사용하는 것은 비용이 많이 든다고 생각합니다(특히 많은 관계에서 헤더가 있는 경우, 수천 개의 레코드가 있습니다).데이터베이스에서 데이터를 취득하여 각 레코드를 작성하기 때문입니다.는 원래 배열을 생성한 후 원래 배열을 반복하여 지정된 블록의 값을 사용하여 새 배열을 구축합니다.

용기를 사용하는 것이 더 빠르고 아마도 가장 빠른 선택일 것이다.

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

Benchmark.measure를 사용한 통계는 다음과 같습니다.

> Benchmark.measure { physician.appointments.map(&:patient_id) }
 => #<Benchmark::Tms:0xb671654 @label="", @real=0.114643818, @cstime=0.0, @cutime=0.0, @stime=0.010000000000000009, @utime=0.06999999999999984, @total=0.07999999999999985> 

> Benchmark.measure { physician.appointments.pluck(:patient_id) }
 => #<Benchmark::Tms:0xb6f4054 @label="", @real=0.033517774, @cstime=0.0, @cutime=0.0, @stime=0.0, @utime=0.0, @total=0.0> 

저는 250개의 예약만 사용하고 있습니다.예약 문서의 : patient_id 및 :physician_id에 인덱스를 추가하는 것을 잊지 마세요!

도움이 되었으면 좋겠네요, 읽어주셔서 감사합니다!

has_many가 아닌 자기 참조 어소시에이션의 관점에서 이 질문에 답하고 싶습니다.

연락처가 있는 CRM이 있다고 칩시다.연락처는 다른 연락처와 관계가 있지만, 두 가지 다른 모델 간에 관계를 만드는 대신 동일한 모델의 두 인스턴스 간에 관계를 만듭니다.연락처는 많은 친구를 사귀고 많은 다른 연락처와 친구가 될 수 있기 때문에 다대다 관계를 맺어야 합니다.

RDBMS 및 ActiveRecord를 사용하는 경우 has_many : ~ 를 사용합니다.따라서 우리는 우정과 같은 결합 모델을 만들어야 합니다.이 모델에는 친구를 추가하는 현재 연락처를 나타내는 contact_id와 친구가 되는 사용자를 나타내는 friend_id라는 두 개의 필드가 있습니다.

하지만 우리는 MongoDB와 Mongoid를 사용하고 있습니다.위와 같이 Mongoid에는 has_many : through 등의 기능이 없습니다.가입 쿼리를 지원하지 않기 때문에 MongoDB에서는 그다지 유용하지 않습니다.따라서 MongoDB와 같은 비 RDBMS 데이터베이스에서 다다 관계를 모델링하려면 양쪽에서 '외부' 키 배열을 포함하는 필드를 사용합니다.

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와 비슷하지만 Join 컬렉션이 필요하지 않으며 외부 키 ID는 관계의 양쪽에 배열로 저장됩니다.

이러한 성질의 관계를 정의할 때 각 문서는 각각의 컬렉션에 저장되며 각 문서에는 배열 형식으로 다른 문서에 대한 "외부 키" 참조가 포함됩니다.

# 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

관련된 연락처와 다수의 실무에 속하는 연락처의 차이점은 무엇입니까?엄청난 차이!하나는 두 실체 사이의 관계입니다.다른 하나는 자기 소개서입니다.

언급URL : https://stackoverflow.com/questions/7000605/how-to-implement-has-many-through-relationships-with-mongoid-and-mongodb

반응형