mongoose克隆对象的问题

本文探讨了使用mongoose在不同版本下克隆文档时遇到的问题。详细解析了在mongoose@4.4.x版本中,由于引入了isNew属性导致的克隆失败,并提供了正确的克隆方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

mongoose克隆对象的问题

@(技术笔记)[mongodb]

问题说明

通过mongoose进行克隆一个对象,就跟如何把大象放到冰箱一样,分为三步
1. 查到docoment
2. 修改docoment的id;
3. 存docoment

代码如下,运行过程没有异常,但是在数据库中却找不到对应记录。更诡异的是,升级mongoose版本前还是好好的!

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');

var Cat = mongoose.model('Cat', {name: String});
new Cat({name: '123'}).save(function (err, doc) {
    var cloneObj = doc;
    cloneObj._id = new Cat()._id;//修改Id;
    new Cat(cloneObj).save(function (err, doc) {
        Cat.findOne({_id:doc._id},function(err,doc2){
            console.log(doc2);
        })
    });
})

比较了升级前后的mongoose版本,发现一个是mongoose@4.3.x,一个是mongoose@4.4.x。

研读mongoose源代码

原来在mongoose@4.4.x版本中,lib/docment.js的下列代码,this.isNew这段代码是在4.4新增的
这里写图片描述
在lib/model.js中,当执行save操作时,判断this.isNew,如果值为false,执行update操作
Alt text
其中where = this.$__where(delta[0]) 再来看看delta[0]是什么?
这里写图片描述
那么where条件:_id =xxx
至此一切都清楚了,我们把docoment用一个新的id赋值,在更新时根据这个mongoose做了一些优化处理,用这个id取进行更新操作。那么数据库什么没有执行就返回了,没有报错,但是结果没有宝座。

这就解释了mongoose@4.3能正常执行的代码,由于mongoose4.4做了优化,反而不能正常执行的原因了。

经验教训

针对不同mongoose版本的问题,保险的做法,克隆时要调用toObject()做转换

    var cloneObj = doc.toObject();

附录,完整的测试用例

通过mocha执行

var mongoose = require('mongoose');
var assert = require('assert');

mongoose.connect('mongodb://localhost/test');
var Cat = mongoose.model('Cat', {name: String});


var objDb;
describe('test clone document by mongoose', function () {
    it('create obj', function (done) {
        new Cat({name:'123'}).save(function(err,doc){
            assert(!err);
            assert(doc);
            Cat.findOne({_id:doc._id},function(err,doc2){
                assert(!err);
                assert(doc2);
                objDb = doc2;
                done();
            })
        });
    });

    it('clone obj by modified _id(mongoose@4.3.3 supported,>=4.4 not supported)', function (done) {
        var cloneObj = objDb;
        cloneObj._id = new Cat()._id;//修改Id;
        new Cat(cloneObj).save(function(err,doc){
            assert(!err);
            assert(doc);
            Cat.findOne({_id:doc._id},function(err,doc2){
                assert(!err);
                assert(doc2);
                done();
            })
        });
    });

    it('clone obj after toObject(), function (done) {
        var cloneObj = objDb.toObject();
        cloneObj._id = new Cat()._id;//修改Id;
        new Cat(cloneObj).save(function(err,doc){
            assert(!err);
            assert(doc);
            Cat.findOne({_id:doc._id},function(err,doc2){
                assert(!err);
                assert(doc2);
                done();
            });
        });
    });
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值