如何使用Rails和Mongoid将mongodb文档直接返回给客户端

时间:2013-04-29 11:42:28

标签: ruby-on-rails mongodb mongoid

如果文档中包含日期时间和要在图形中显示的数据,如何直接返回查询结果而不从BSON转换为Ruby,最后转换为JSON?

问题:在BSON中为客户端正确存储时间值,但是涉及Ruby会将其转换为时间对象,我必须time.to_i * 1000才能在返回的JSON中正确存储。在任何情况下,我都不需要转换任何数据,所以这只是一种浪费。

我在Heroku + MongoHQ上运行Rails,Mongoid。我想让Rails应用程序执行查询授权,但不将响应转换为Ruby对象。

def show_graph
  raw_bson = TheModel.all_raw_documents_matching(query_params)
  raw_bson.to_json  
  # Alternatively, this BSON to JSON could be happening client side. 
  # side. Whatever, just don't convert to ruby objects...
end

1 个答案:

答案 0 :(得分:0)

你的问题有很多观点。 我认为to_json方法处理DateTime ruby​​对象的序列化更为关键,而不是BSON反序列化。

我想到的最简单,最棘手的方法是覆盖as_json类的Time方法:

class Time
 def as_json(options={})
    self.to_i * 1000
 end
end

hash = {:time => Time.now}
hash.to_json # "{\"a\":1367329412000}" 

您可以将其放入初始化程序中。这是一个非常简单的解决方案,但您必须记住,您的应用中的每个ruby Time对象都将使用您的自定义方法进行序列化。这可能没问题,或者不是,它确实是很难说,有些宝石可能依赖于此,或不是。

更安全的方法是编写一个包装器并调用它而不是to_json

def to_json_with_time
  converted_hash = self.attributes.map{|k,v| {k => v.to_i * 1000 if v.is_a?(Time)} }.reduce(:merge)
  converted_hash.to_json
end

最后,如果你真的想要覆盖Mongoid序列化和反序列化对象的方式,如果你想跳过BSON过程,你必须定义mongoizedemongoize方法。 您可以在此处找到文档:Custom Field Serialization

**更新**

问题是序列化而不是反序列化。如果从查询中获得原始BSON,则仍然具有Time ruby​​对象的字符串表示形式。 您不能将BSON直接转换为JSON,因为无法将时间的字符串表示转换为整数表示而不从ruby Time类转换。

这是一个如何使用Mongoid自定义字段序列化的示例。

class Foo
  include Mongoid::Document

  field :bar, type: Time
end


class Time

  # The instance method mongoize take an instance of your object, and converts it into how it will be stored in the database
  def mongoize
    self.to_i * 1000
  end

  # The class method mongoize takes an object that you would use to set on your model from your application code, and create the object as it would be stored in the database
  def self.mongoize(o)
    o.mongoize
  end

  # The class method demongoize takes an object as how it was stored in the database, and is responsible for instantiating an object of your custom type.
  def self.demongoize(object)
    object
  end

end

Foo.create(:bar => Time.now) #<Foo _id: 518295cebb9ab4e1d2000006, _type: nil, bar: 1367512526> 
Foo.last.as_json # {"_id"=>"518295cebb9ab4e1d2000006", "bar"=>1367512526}