问题描述
所以我有两个看起来像这样的类
class Branch
include MongoMapper::Document
many :builds
end
class Build
include MongoMapper::Document
belongs_to :branch
end
并且如果我们要访问Branch
类中的Build
数据。我可以像下面这样
builds = Build.where(___)
builds.each do |build|
puts "#{build.branch.name} build number #{build.number}"
end
但这会触发警报,导致发出N + 1个查询,因为它进行了太多的独立数据库查询。很好的解决方案是使用如下所示的Eager Load
builds = Build.where(____).includes(:branches)
builds.each do |build|
puts "#{build.branch.name} build number #{build.number}"
end
当我从他们的文档中查找时,MongoMapper中的急切加载或.includes()
不可用(我希望我错了)。但是在MongoId中可用。但是,我暂时不打算从MongoMapper更改为MongoId。你知道这个转身吗?也许可以减少查询。
解决方法
根据docs Mongoid的#includes
“ ...,将根据对id的额外查询将所有ID匹配的文档加载到身份映射中。”
所以根本没有魔术-听起来它只是执行一个附加查询以获取关联的实体,并通过O(1)读取以某种数据结构将它们保存在内存中(例如,Ruby中的Hash) 。您可以自己进行操作(免责声明: kinda伪代码即将发布,作为参考,但尚未提供解决方案)
builds = #...
branches = Branch.where(id: builds.map(&:id)).to_h { |br| [br.id,br] }
builds.each do |build|
puts "#{branches[build.branch_id]&.name} build number #{build.number}"
end
但是请注意:如果您经常需要进行这种记忆,则可能是信号表明数据模型不是基于文档的数据库的最佳选择-嵌入式文档可能是一种更有效的解决方案...