当前位置:  开发笔记 > 数据库 > 正文

如何实现has_many:通过与Mongoid和mongodb的关系?

如何解决《如何实现has_many:通过与Mongoid和mongodb的关系?》经验,为你挑选了3个好方法。

使用Rails指南中的这个修改示例,如何使用mongoid建模关系"has_many:through"关联?

挑战是mongoid不支持has_many:通过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

Steve.. 150

Mongoid没有has_many:through或等效功能.它对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

换句话说,你会消除连接表,它会对has_many产生类似的效果:就访问"另一方"而言.但在你的情况下,这可能不合适,因为你的连接表是一个Appointment类,它携带一些额外的信息,而不仅仅是关联.

如何对此进行建模在某种程度上取决于您需要运行的查询,但似乎您需要添加约会模型并定义与患者和医生的关联,如下所示:

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大小限制,如果您有大量的会议记录,可能会发挥作用.



1> Steve..:

Mongoid没有has_many:through或等效功能.它对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

换句话说,你会消除连接表,它会对has_many产生类似的效果:就访问"另一方"而言.但在你的情况下,这可能不合适,因为你的连接表是一个Appointment类,它携带一些额外的信息,而不仅仅是关联.

如何对此进行建模在某种程度上取决于您需要运行的查询,但似乎您需要添加约会模型并定义与患者和医生的关联,如下所示:

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大小限制,如果您有大量的会议记录,可能会发挥作用.


+1很棒的答案,也是一个很好的问题.
+1非常好的答案,仅供参考,mongodb大小限制已增加到16 MB.

2> Steven Sorok..:

为了扩展这一点,这里的模型扩展了与has_many非常类似的方法:通过返回查询代理而不是记录数组来从ActiveRecord:

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


这肯定有助于我的检索方法返回一个搞乱分页的数组.

3> 小智..:

Steven Soroka解决方案非常棒!我没有评论答案的声誉(这就是为什么我要添加一个新的答案:P)但我认为使用地图建立关系是昂贵的(特别是如果你的has_many关系有猎人|成千上万的记录)因为它得到了来自数据库的数据,构建每个记录,生成原始数组,然后遍历原始数组,以使用给定块中的值构建一个新数组.

使用pluck更快,也许是最快的选择.

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.measure { physician.appointments.pluck(:patient_id) }
 => # 

我只使用250个约会.不要忘记在约会文档中添加索引:patient_id和:physician_id!

我希望它有所帮助,感谢阅读!

推荐阅读
ERIK又
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有