Mongomapper: copy a document into a new document
Asked Answered
I

3

5

I have a mongomapper document with embedded documents, and want to make a copy of it.

In essence, what I am trying to do is something like this:

customer = Customer.find(params[:id])
new_customer = Customer.new
new_customer = customer
new_customer.save

So I want to end up with two different mongomapper documents, but with identical content.

Any ideas how this should be done?

Incursion answered 9/3, 2011 at 6:4 Comment(1)
From a little reading I've done, I figure the only way to do this is to loop through the embedded documents in the parent document, get their attributes, create new documents by copying these attributes over for each one, until I have a copy of the document. Can anyone think of another way?Incursion
M
4

To accomplish this, you need to change the _id. Documents with the same _id are assumed to be the same document so saving a document with a different _id will create a new document.

customer = Customer.find(params[:id])
customer._id = BSON::ObjectId.new # Change _id to make a new record
  # NOTE: customer will now persist as a new document like the new_document 
  # described in the question.
customer.save # Save the new object

As an aside, I would be inclined to store the old _id somewhere in the new record so I could keep track of who derived from who, but it is not necessary.

Mossy answered 21/3, 2011 at 17:9 Comment(1)
Nice, I can see how I can combine your creation of new ids with the way I deal with embedded documents, i.e. give new copies of the document and its embedded documents their new ids.Incursion
H
4

You should simply be able to do this:

duplicate_doc = doc.clone
duplicate_doc.save
Hector answered 15/11, 2011 at 20:30 Comment(0)
I
0

I don't think it is possible (or valid) to create copies of an existing document in mongodb/mongomapper because it seems to me that there would be a clash of the document/embedded documents and their ids of the original and copied documents.

So I solved my problem by copied the contents of the documents into new documents, rather than the documents themselves. Here is a sample:

inspection = Inspection.find(params[:inspection_id])  #old document
new_inspection = Inspection.create                    #new target document
items = inspection.items                              #get the embedded documents from inspection

items.each do |item|                                  #iterate through embedded documents
    new_item = Item.create                            #create a new embedded document in which
                                                      #  to copy the contents of the old embedded document
    new_item.area_comment = item.area_comment         #Copy contents of old doc into new doc
    new_item.area_name = item.area_name
    new_item.area_status = item.area_status
    new_item.clean = item.clean
    new_item.save                                     #Save new document, it now has the data of the original
    new_inspection.items << new_item                  #Embed the new document into its parent
  end

 new_inspection.save                                  #Save the new document, its data are a copy of the data in the original document

This actually worked very well in my scenario. But I am curious if people have a different solution.

Incursion answered 10/3, 2011 at 6:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.