Deep clone document with built-in associations

How would you do deep cloning of a document in MongoDB (mongoid)

I tried something like this:

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

But after that, I have problems deserializing the values.

How to make a deep clone with all the attributes of documents except _id?

Edit: After running the Zachary example, I had problems with a custom serialization class for duplicate 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 

The object is zero for duplicate documents. Car.find (old_id). Attributes do not really include a custom serialization field, why is this and how to enable it?

+6
source share
2 answers

You do not need to call .clone, you can use the raw data from attributes . For example, the method / example below will give new identifiers in the entire document if it finds it.

 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 now you have a copy of the car. This is inefficient, though, since it has to go through the entire hash for writing in order to find out if there are embedded documents in the embedded document. You would be better off resetting the structure yourself if you know how it will be, for example, if you have parts built into the machine, then you can simply 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} 

This is much more efficient than just creating a reset.

+7
source

You should use Car.instantiate if you have localized fields, so the code

 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 did not find the best.

0
source

All Articles