具有嵌入关联的深层克隆文档

时间:2012-01-09 18:58:14

标签: mongodb mongoid

你将如何深入克隆MongoDB中的文档(mongoid)

我尝试过这样的事情;

original = Car.find(old_id)
@car = original.clone
@car._id = BSON::ObjectId.new

但是之后我对这些值的反序列化产生了问题。

如何使用除_id?

之外的所有文档属性进行深度克隆

编辑: 在遵循Zachary的示例后,我遇到了一些针对重复文档的自定义序列化类的问题。

class OptionHash
  include Mongoid::Fields::Serializable

  # Convert the keys from Strings to Symbols
  def deserialize(object)
    object.symbolize_keys!
  end

  # Convert values into Booleans
  def serialize(object)
    object.each do |key, value|
    object[key] = Boolean::MAPPINGS[value]
  end
end

对于重复文档,对象为零。 Car.find(old_id).attributes确实不包含自定义序列化的字段,为什么会这样,我该如何包含它呢?

2 个答案:

答案 0 :(得分:7)

您无需为此调用.clone,您可以使用attributes中的原始数据。例如,如果找到一个,则下面的方法/示例将在整个文档中给出新的ID。

def reset_ids(attributes)
    attributes.each do |key, value|
        if key == "_id" and value.is_a?(BSON::ObjectId)
            attributes[key] = BSON::ObjectId.new
        elsif value.is_a?(Hash) or value.is_a?(Array)
            attributes[key] = reset_ids(value)
        end        
    end
    attributes
end


original = Car.find(old_id)
car_copy = Car.new(reset_ids(original.attributes))

你现在有了Car的副本。这是低效的,因为它必须通过记录的整个哈希来确定嵌入文档中是否存在任何嵌入文档。如果您知道它的结构,最好自己重置结构,例如,如果您将部件嵌入汽车,那么您可以这样做:

original = Car.find(old_id)
car_copy = Car.new(original.attributes)
car_copy._id = BSON::ObjectId.new
car_copy.parts.each {|p| p._id = BSON::ObjectId.new}

这比仅进行通用重置更有效率。

答案 1 :(得分:0)

如果您有本地化字段,则必须使用Car.instantiate,因此代码为

def reset_ids(attributes)
    attributes.each do |key, value|
        if key == "_id" && value.is_a?(Moped::BSON::ObjectId)
            attributes[key] = Moped::BSON::ObjectId.new
        elsif value.is_a?(Hash) || value.is_a?(Array)
            attributes[key] = reset_ids(value)
        end        
    end
    attributes
end

car_original = Car.find(id)
car_copy = Car.instantiate(reset_ids(car_original.attributes))
car_copy.insert

这个解决方案不是很干净但我找不到更好的。