Deep clone document with embedded associations

前端 未结 2 1388
后悔当初
后悔当初 2020-12-17 01:03

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.clon         


        
相关标签:
2条回答
  • 2020-12-17 01:41

    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.

    0 讨论(0)
  • 2020-12-17 01:57

    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.

    0 讨论(0)
提交回复
热议问题