处理Mongoid中的自定义对象数组

时间:2015-09-04 16:38:50

标签: ruby mongoid

我在创建包含数组自定义对象的Mongoid文档时遇到了一些问题。

我的具体情况我打算存储一组BaseDevice个对象。 BaseDevice类已经使用Mongoid的custom fields支持进行了分类和序列化。这在单个对象上非常有效。

为了存储BaseDevice的数组,我创建了以下类:

class BaseDeviceArray < Array
  class << self  
    def demongoize(object)
      object ? object.map{ |obj| BaseDevice.demongoize obj } : new
    end

    def evolve(object)
      case
        when BaseDeviceArray then object.mongoize
        else object
      end
    end
  end

  def mongoize
    self.map(&:mongoize)
  end
end

mongoid文档看起来像这样

class MongoPeriph
  include Mongoid::Document
  field :devices, type: BaseDeviceArray
end

假设some_devices是一个包含两个BaseDevice个实例的数组。 会发生以下情况:当我将some_devices分配给正常工作的MongoPeriph实例的设备字段时。

mp = MongoPeriph.create
mp.devices = some_devices
mp.devices # => [#<BaseDevice:0x007fa84bac0080>,#<BaseDevice:0x007fa84baaff78>]

当尝试将pushpopshiftunshift方法发送到mongoid文档中的设备字段时,似乎什么也没发生。更改未显示在mp对象上。此外,当通过索引引用其中一个对象时(即,在调用mp.devices[0].some_method时),世界不会改变。

从数组中弹出对象时,在每个pop上都会给出一个新对象。这是预期的,因为反序列化器为每个BaseDevice实例化一个新的pop对象,但内部字段没有更新,即对象停留在那里,一个可以无休止地弹出。

使用与mongoid文档分开的BaseDeviceArray按预期工作:

foo = BaseDeviceArray.new
foo << BaseDevice.new

导致带有BaseDevice对象的数组。

顺便说一下。我在网上找到了另一个approach。这是实现我需要的更通用的方式,但它是 monkey-patches Mongoid。我试图避免的东西。此外,该解决方案似乎与我的方法有相同的问题。

1 个答案:

答案 0 :(得分:1)

您的代码中的问题是您拥有#mongoize(实例)方法,但实际上您需要::mongoize(类)方法。你永远不会创建BaseDeviceArray的实例,因此实例方法是无用的。

以下是我如何使用::mongoize方法实现我在mongo Hash中使用带有数组值的单个键的示例。另外,我想将结果数组放入一个带有ids的哈希值作为键,以便于查找。

def demongoize(hash)
  return validate_hash(hash)["TestRecord"].each_with_object({}) do |r, m|
    rec = TestRecord.new(r)
    m[rec.case_id] = rec
  end
end

def mongoize(object)
  case object
  when Array then {"TestRecord" => object.map(&:mongoize)}
  when Hash
    if object["TestRecord"]
      # this gets actually called when doing TestRun.new(hash)
      mongoize(demongoize(object))
    else
      {"TestRecord" => object.values.map(&:mongoize)}
    end
  else raise("dunno how to convert #{object.class} into records JSON")
  end
end

def evolve(object)
  # can't see how we want to process this here yet
  # docs.mongodb.com/ruby-driver/master/tutorials/6.0.0/mongoid-documents
  object
end

我想很久以前就完成了op任务,但是觉得有人觉得它很有用。