2012-01-09 56 views
6

您如何去深入克隆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確實不包含具有自定義序列化的字段,爲什麼是這樣以及如何包含它?

+0

你能對問題更具體嗎? – Barrie 2012-01-09 19:21:54

+0

你以後有什麼問題? – 2012-01-09 23:29:40

+0

我想問題是嵌入式文檔的ID不會更新。即與原始文檔中嵌入文檔的ID衝突。 – Yeggeps 2012-01-10 12:59:09

回答

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

而你現在有一個車的副本。這是效率低下的,因爲它必須通過記錄的整個散列才能確定嵌入文檔中是否有嵌入式文檔。你會過得更好重置自己的結構,如果你知道它會如何爲,例如,如果你有嵌入到汽車零件,那麼你可以這樣做:

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} 

這是很多比更有效只是做一個通用的重置。

+0

嗨,謝謝,更新了這個問題,因爲我遇到了這個問題。 – Yeggeps 2012-01-10 15:20:46

+0

Hrm。我對Mongoid :: Fields :: Serializable沒有多少經驗。我會在調用'original.attributes'時檢查是否傳遞了什麼類型的數據。你得到序列化的數據還是反序列化的數據?它可能是傳遞反序列化數據的問題,因此您需要在克隆之前將其序列化。 – 2012-01-10 15:51:47

+0

優秀的帖子..我只需要考慮rails3中的mass_assignment安全性就可以完成這項工作。 通過從模型中刪除attr_accessible它像一個魅力工作..謝謝! – Tigraine 2012-10-08 09:28:29

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 

這個解決方案不是很乾淨,但我沒有找到更好的。