【问题标题】:Deep clone document with embedded associations具有嵌入式关联的深度克隆文档
【发布时间】:2012-01-09 18:58:13
【问题描述】:

您将如何在 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 确实不包含自定义序列化的字段,为什么会这样,我该如何包含它?

【问题讨论】:

  • 您能具体说明一下问题吗?
  • 以后有什么问题?
  • 我想问题是嵌入文档的 ID 没有得到更新。即与原始文档中嵌入文档的 id 冲突。

标签: mongodb mongoid


【解决方案1】:

您无需为此调用 .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}

这比仅仅进行通用重置要高效得多。

【讨论】:

  • 您好,谢谢,更新了问题,因为我在使用这种方法时遇到了一些问题。
  • 人力资源部。我对 Mongoid::Fields::Serializable 没有太多经验。当您致电original.attributes 时,我会检查正在传递的数据类型。你得到的是序列化数据还是反序列化数据?它可能是传递反序列化数据的问题,因此您需要在克隆之前对其进行序列化。
  • 优秀的帖子.. 我只需要考虑 rails3 中的 mass_assignment 安全性就可以完成这项工作。通过从模型中删除 attr_accessible 它就像一个魅力......谢谢!
  • 我收到错误NameError: uninitialized constant BSON_id 持有 String 值。
  • 由于Mongoid切换到Moped,你必须使用:Moped::BSON::ObjectId
【解决方案2】:

如果您有本地化字段,则必须使用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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-25
    相关资源
    最近更新 更多