复制/克隆mongoose文档实例的最简单方法是什么?

35

我的方法是获取文档实例,然后从实例字段创建一个新的文档。我相信有更好的方法来做到这一点。

9个回答

92

你需要重置 d1.isNew = true;,例如:

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

3
你本可以评论她的回答或编辑那个回答! - Amr Saber
这也不起作用。也许是版本问题,因为这是2014年的。也许以前可以工作。 - David J

16

您能澄清一下“复制/克隆”的含义吗?您是想在数据库中创建一个重复的文档副本吗?还是只是想让程序中有两个具有重复数据的var

如果您只是这样做:

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 将是你的程序中同一文档的两个“副本”。
或者,如果你想将一个新副本插入到数据库中(尽管具有不同的 _id),那么操作如下:
Model.findById(yourid).exec(
    function(err, doc) {
        var d1 = doc;
        d1._id = /* set a new _id here */;
        d1.isNew = true;
        d1.save(callback);
    }
);

如果你从一开始就这样做,即创建了一些文档d1,那么你只需调用两次save而不设置_id:

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

你的数据库中现在将会有两个文档拥有不同的 _id ,但其他所有字段都相同。

这样是否更加清晰易懂了呢?


4
是的,我最终获得了这个“doc”,将“_id”移除并保存 :) - fusio
你是如何移除 _id 的? - JoeTidee
2
@JoeTidee 你可以使用 delete doc._id 来从 doc 对象中删除 _id 属性! - Will Brickner
4
很遗憾,这并没有回答这个问题。要真正克隆一个文档,你需要执行以下操作:new Model(doc.toObject()) - losnir
抱歉,但这个答案不好,你只能这样做:var doc1 = doc.toJSON(); var doc2 = doc.toJSON(); 然后你就有了两个具有相同数据的对象,没有查询。 - Ninja Coding
显示剩余2条评论

10

我的观点:

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

1
这里使用 exec 不是多余的吗? - sean

3
那么,很多答案对简单文档都适用,但是在尝试复制复杂文档时可能会出现错误情况。
例如,如果您有子文档的数组,则可以在复制的文档中出现重复的_id,这可能会导致以后出现细微的错误。
要深度克隆mongoose文档,建议尝试以下内容:
//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 字段。

2
以下代码用于克隆文档:
Model.findById(yourid).exec(
        function(err, doc) {
            var newdoc = new Model(doc);
            newdoc._id = mongoose.Types.ObjectId();
            newdoc.save(callback);
        }
    );

1

要简单克隆,请使用以下代码:

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

这可能更简单地表述为您只需复制对象属性。我发现任何方法都不起作用。 - David J

1
const cloneDoc = (doc, model)=>{
  const copyDoc = new Model({
    ...doc.toObject(),
    _id: undefined,
  });
  copyDoc.isNew = true;
  return copyDoc;
}

0

将文档复制到同一集合或不同集合中,首先获取(查询)数据并复制数据。然后从新列表中删除 _id,因为您无法从当前数据中删除它。这将允许您插入一个新记录,并从 mongodb 分配新的 _id。

将 searchBy 更改为您要查找文档的内容。将 collectionA 和 collectionB 更改为要创建副本的集合名称。目前,我们正在 collectionA 中搜索并将数据复制到 collectionB 中。

collectionA.find(searchBy).exec(function (err, doc) {
      // create a new copy
      let newDoc = { ...doc[0] }._doc;

      // delete property from new copy (remove _id).
      delete newDoc._id;

      // insert copy into db
      var newdoc = new collectionB(newDoc);
      newdoc.save();
    });

-1

此示例将克隆模式,而不是文档。 - taseenb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接