【问题标题】:Handling Arrays of custom objects in Mongoid在 Mongoid 中处理自定义对象数组
【发布时间】:2015-09-04 16:38:49
【问题描述】:

我在创建包含自定义对象的 array 的 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 文档中的 devices 字段时,似乎没有任何反应。更改未出现在 mp 对象上。此外,当按索引引用其中一个对象时(即调用mp.devices[0].some_method 时),世界不会改变。

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

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

foo = BaseDeviceArray.new
foo << BaseDevice.new

产生一个带有 BaseDevice 对象的数组。

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

【问题讨论】:

  • 添加这些关系导致NoMethodError: undefined method '[]' for nil:NilClass from.../mongoid-4.0.2/lib/mongoid/relations/accessors.rb:113:in 'needs_no_database_query?' 似乎它希望我完全“mongoize”带有字段等的BaseDevice(和派生)类。我是什么试图实现的是将普通对象(在数组中)嵌入到mongoid文档中。
  • 我不知道究竟是什么使对象能够将其嵌入文档中。我认为,存在 de/mogoize 方法应该使其成为“合格”的 mongo 对象。与此同时,我或多或少地使用了嵌入式关系。我忘记在BaseDeviceinitializer 中添加super,这让mongoid 偏离了轨道。包括Mongoid::Attributes::Dynamic 之后,它似乎工作了。无论如何,我宁愿拥有没有所有 Mongo 混乱的“普通”对象。

标签: ruby mongoid


【解决方案1】:

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

这是我如何执行::mongoize 方法的示例,其中我实际上在mongo 中有一个Hash,它带有一个带有数组值的键。此外,我想将生成的数组制作成一个以 id 作为键的散列,以便于查找。

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 任务很久以前就完成了,但我认为有人可能会觉得它有用。

【讨论】:

    猜你喜欢
    • 2011-12-05
    • 2022-06-30
    • 2023-04-02
    • 2016-05-10
    • 2019-07-28
    • 1970-01-01
    • 2018-01-09
    • 1970-01-01
    • 2014-12-16
    相关资源
    最近更新 更多