web-dev-qa-db-ja.com

Mongooseドキュメントインスタンスをコピー/クローンする最も簡単な方法は?

私のアプローチは、ドキュメントインスタンスを取得し、インスタンスフィールドから新しいインスタンスを作成することです。私はそれを行うためのより良い方法があると確信しています。

17
fusio

「コピー/クローン」の意味を明確にできますか?データベースに複製ドキュメントを作成しようとしていますか?または、重複するデータを持つ2つのvarsをプログラムに含めようとしているだけですか?

あなただけの場合:

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"
            }); 
    });

この場合、xyは、プログラム内の同じドキュメントの2つの「コピー」になります。

または、ドキュメントの新しいコピーをデータベースに挿入したい場合(別の_idを使用すると思いますが)、次のようになります。

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

または、最初からこれを行っている場合、別名d1というドキュメントを作成した場合は、_idを設定せずにsaveを2回呼び出すだけです。

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

これで、_idが異なる2つのドキュメントと、データベース内の他のすべてのフィールドが同一になります。

これで少しわかりやすくなりますか?

11
Amalia

上記のAmeliaの応答でドキュメントを複製する次のコード機能しません

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

リセットする必要もありますd1.isNew = true;のように:

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

ドキュメントを複製する次のコード:

Model.findById(yourid).exec(
        function(err, doc) {
            var newdoc = new Model(doc);
            newdoc ._id = mongoose.Types.ObjectId();
            newdoc .save(callback);
        }
    );
1
Asad Fida

単にクローンを作成するには、これを使用します:

Context.findOne({
    _id: context._id
})
    .then(function(c) {
        c._id = undefined;
        c.name = context.name;
        c.address = context.address;
        c.created = Date.now();
        return Context.create(c.toObject());
    }).then(function(c) {
        return res.json({
            success: true,
            context: context
        });
    }).catch(function(err) {
        next(err, req, res);
    });
0
Espinasse

したがって、これらの回答の多くは単純なドキュメントではうまく機能しますが、複雑なドキュメントの深いクローンを作成しようとすると、エラーが発生する可能性があります。

たとえば、サブドキュメントの配列がある場合、コピーされたドキュメントで_idが重複してしまい、後で微妙なバグが発生する可能性があります。

マングースドキュメントのディープクローンを作成するには、次のようなことを試すことをお勧めします。

//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();

これはかなり安全なアプローチであり、オブジェクトのすべての部分が、保存時に新しく生成された_idフィールドを使用して適切に複製されることを保証します。

0
Clayton Gulick