Easiest way to copy/clone a mongoose document instance?

35,820

Solution 1

Can you clarify what you mean by "copy/clone"? Are you going trying to create a duplicate document in the database? Or are you just trying to have two vars in your program that have duplicate data?

If you just do:

Model.findById(yourid).exec(
    function(err, doc) { 
        var x = doc; 
        Model.findById(yourid).exec(
            function(err, doc2) {
                var y = doc2;
                // right now, x.name and y.name are the same
                x.name = "name_x";
                y.name = "name_y";
                console.log(x.name); // prints "name_x"
                console.log(y.name); // prints "name_y"
            }); 
    });

In this case, x and y will be two "copies" of the same document within your program.

Alternatively, if you wanted to insert a new copy of the doc into the database (though with a different _id I assume), that would look like this:

Model.findById(yourid).exec(
    function(err, doc) {
        var d1 = doc;
        d1._id = /* set a new _id here */;
        d1.isNew = true;
        d1.save(callback);
    }
);

Or if you're doing this from the outset, aka you created some document d1, you can just call save twice without setting the _id:

var d1 = new Model({ name: "John Doe", age: 54 });
d1.save(callback);
d1.save(callback);

There will now be two documents with differing _id's and all other fields identical in your database.

Does this clarify things a bit?

Solution 2

You need to reset d1.isNew = true; as in:

Model.findById(yourid).exec(
    function(err, doc) {
        doc._id = mongoose.Types.ObjectId();
        doc.isNew = true; //<--------------------IMPORTANT
        doc.save(callback);
    }
);

Solution 3

My two cents:

const doc = await DocModel.findById(id);
let obj = doc.toObject();
delete obj._id;
const docClone = new DocModel(obj);
await docClone.save();

Solution 4

So, a lot of these answers will work well for simple docs, but there could be an error case when you're trying to make a deep clone of complex documents.

If you have arrays of subdocs, for example, you can end up with duplicate _ids in your copied document, which can cause subtle bugs later.

To do a deep clone of a mongoose doc, I suggest trying something like:

//recursively remove _id fields
function cleanId(obj) {
    if (Array.isArray(obj))
        obj.forEach(cleanId);
    else {
        delete obj['_id'];
        for (let key in obj)
            if (typeof obj[key] == 'object')
                cleanId(obj[key]);
    }
}

let some_doc = await SomeModel.findOne({_id: some_id});
let new_doc_object = cleanId(some_doc.toObject());
let new_doc = new SomeModel(new_doc_object);
await new_doc.save();

This is going to be a pretty safe approach, and will ensure that every part of your object is cloned properly with newly generated _id fields on save.

Solution 5

The following code to clone documents:

Model.findById(yourid).exec(
        function(err, doc) {
            var newdoc = new Model(doc);
            newdoc._id = mongoose.Types.ObjectId();
            newdoc.save(callback);
        }
    );
Share:
35,820

Related videos on Youtube

fusio
Author by

fusio

Updated on January 25, 2022

Comments

  • fusio
    fusio over 2 years

    My approach would be to get the document instance, and create a new one from the instance fields. I am sure there is a better way to do it.

  • fusio
    fusio almost 11 years
    Yes, indeed, I ended up getting the doc, removing _id and saving :)
  • JoeTidee
    JoeTidee over 7 years
    How did you remove the _id?
  • Will Brickner
    Will Brickner over 7 years
    @JoeTidee You can use delete doc._id will remove the _id property from the doc object!
  • losnir
    losnir almost 7 years
    This does not answer the question unfortunately. To truly clone a document, you would do: new Model(doc.toObject()).
  • Iron_Man
    Iron_Man over 6 years
    What are the approaches for copying the entire collection and create it with new name Through Mongoose? As I know how to clone/Copy the collection through cmd, But this things not work on mongoose. Any help is appreciated
  • Ninja Coding
    Ninja Coding almost 6 years
    sorry but this answer is bad, you just can do: var doc1= doc.toJSON(); var doc2= doc.toJSON(); and you have 2 objects with same data, no query.
  • Amr Saber
    Amr Saber about 5 years
    you could have commented on her answer or edited the answer !
  • David J
    David J over 3 years
    Great answer but, this does not work as expected. You cannot delete an _id on a Mongoose object. Second, the id is created on the local object, so saving twice does not create two identical objects. It just saves the same document twice. Even if you create a new id. This might be a version thing as this answer is from 2013. Maybe it used to work.
  • David J
    David J over 3 years
    This also does not work. Perhaps it's a version thing since this is 2014. Maybe it used to work.
  • David J
    David J over 3 years
    This might be more simply stated as you just have to copy object properties. I've not found any of the approaches to work.
  • sean
    sean almost 3 years
    Isn't exec redundant here
  • taseenb
    taseenb about 2 years
    This example will clone the schema, not the document