• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

Ruby在使用MongoDB时,对Cursor的重新包装

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

MongoDB是个好东西,作为非关系数据库,十分的便利,符合Ruby的一贯精神

在使用中,出现了以下问题:
  调用 DB.collection.find(...) 返回的对象是 Cursor,而Cursor#each 或 Cursor#next_document ... 的对象是OrderedHash
  我们难免会设计数据库层来简化数据库通讯,我们设定以下语境来描述这个问题:

 

class Sample
	...
	def self.find(hash = nil)
		cursor = self.collection.find(hash)
		cursor
	end
	
	def self.to_sample(ordered_hash)
		...
	end
	...
end

 Sample 对应于一个Collection,Sample#find返回一个cursor,而我们使用的方法大致如下:

 

Sample.find.each |hash|
	sample = Sample.to_sample(hash)
	...
end

这是段极其Ugly的代码,每次我们从Sample#find获得的对象都要 to_sample一下才能使用,不得不考虑Ruby强大解决能力:

 

class Sample
	...
	def initialize(ordered_hash)
		...
	end
	#instead of :
	#def self.to_sample(ordered_hash)
	#	...
	#end
	
	def self.find(hash = nil)
		cursor = self.collection.find(hash)
		class << cursor
			alias :old_next_document :next_document
			def next_document
				hash = old_next_document
				Sample.new(hash)
			end
		end
		cursor
	end	
	...
end

 

 

 

对于cursor实例,采用了Ruby 的 singleton class (区别于设计模式中的单例模式),动态包装了next_document方法(next_document 是 each 等其他方法的基础,是Cursor中唯一获取记录的函数),Sample.find.next_document 返回 Sample对象,一切顺利,这样看似解决了问题
但是当我们有了多个Collection类,并需要提取出一个基类时问题就来了:
  假设我们的基类叫Coll,代码如下:
class Coll
	...
	def initialize(ordered_hash)
		...
	end
	#instead of :
	#def self.to_sample(ordered_hash)
	#	...
	#end
	
	def self.find(hash = nil)
		cursor = self.collection.find(hash)
		class << cursor
			alias :old_next_document :next_document
			def next_document
				hash = old_next_document
				Coll.new(hash)
			end
		end
		cursor
	end	
	...
end
我们只是将Sample换成了Coll,而next_document中的Coll.new(hash)很显然不符合我们的要求(不能初始化成适当的子类,只能生成Coll类实例) 。比如此时我们调用Sample.find.next_document,获得的就只能是Coll类的实例(当然也很有可能出错)。问题集中在 Singleton class 的代码没有根据调用类(Sample)动态生成,当使用Ruby的时候,很显然这不可饶恕:
class Coll
	...
	def initialize(ordered_hash)
		...
	end
	#instead of :
	#def self.to_sample(ordered_hash)
	#	...
	#end
	
	def self.find(hash = nil)
		cursor = self.collection.find(hash)
		cursor.instance_eval <<-EOT
			alias :old_next_document :next_document
			def next_document
				hash = old_next_document
				#{self}.new(hash)
			end
		EOT
		cursor
	end	
	...
end
class Sample < Coll
end
It's better , ha. 我们动态生成了字符串作为执行代码,为单独的cursor实例生成了单独的next_document方法,返回特定的对象(Sample.find.each 返回 Sample对象,Blurblur.find.each 返回Blurblur对象)

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
ruby的内存管理发布时间:2022-07-14
下一篇:
RubyonRails-细节中的精彩发布时间:2022-07-14
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap