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操作
其中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();
});
});
});
});