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

发布于 2024-12-25 18:56:35 字数 691 浏览 0 评论 0原文

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

How would you go about deep cloning a document in MongoDB (mongoid)

I've tried something like this;

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

But I get problems deserialization of the values afterwards.

How can I make a deep clone with all the documents attributes except the _id?

Edit:
After following Zachary's example I got some problems with a custom serialization class for the duplicated documents.

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

Object is nil for duplicated documents.
Car.find(old_id).attributes indeed doesn't include the field with the custom serialization, why is that and how can I include it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

左岸枫 2025-01-01 18:56:35

您不需要对此调用 .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}

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

You don't need to call .clone on this, you can use the raw data from attributes. For example the below method/example will give new ids throughout the entire document if it finds one.

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))

And you now have a copy of Car. This is inefficient though as it has to go through the entire hash for the record to figure out if there are any embedded documents in an embedded document. You would be better off resetting the structure yourself if you know how it'll be, for example, if you have a parts embedded into car, then you can just do:

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}

Which is a lot more efficient than just doing a generic reset.

思念满溢 2025-01-01 18:56:35

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

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

You have to use Car.instantiate if you have localized fields so the code is

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

This solution is not very clean but i don't have found better.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文