使用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大小限制,如果您有大量的会议记录,可能会发挥作用.
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大小限制,如果您有大量的会议记录,可能会发挥作用.
为了扩展这一点,这里的模型扩展了与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
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!
我希望它有所帮助,感谢阅读!