Mongoose覆盖文档,而不是`$ set`字段

说,我有一个文件:

{ _id: 'some_mongodb_id', name: 'john doe', phone: '+12345678901', } 

我想更新这个文件:

 .findOneAndUpdate({_id: 'some_mongodb_id'}, {name: 'Dan smith'}) 

结果应该是这样的:

 { _id: 'some_mongodb_id', name: 'Dan smith', } 

应该删除未指定的属性。

我怎么做?

实际上,实际上mongoose实际上是在“掩盖”下面的更新,实际上这是你提交给一个常规的MongoDB函数的默认动作。

因此,mongoose认为这是一种“方便”的“智慧”方法,可以“设定”你想在这里发出一套$set指令。 由于在这种情况下实际上不想这样做,所以在传递给任何.update()方法的选项中,通过{ overwrite: true }closures该行为:

作为一个完整的例子:

 const mongoose = require('mongoose'), Schema = mongoose.Schema; mongoose.Promise = global.Promise; mongoose.set('debug',true); const uri = 'mongodb://localhost/test', options = { useMongoClient: true }; const testSchema = new Schema({ name: String, phone: String }); const Test = mongoose.model('Test', testSchema); function log(data) { console.log(JSON.stringify(data,undefined,2)) } (async function() { try { const conn = await mongoose.connect(uri,options); // Clean data await Promise.all( Object.keys(conn.models).map( m => conn.models[m].remove({}) ) ); // Create a document let test = await Test.create({ name: 'john doe', phone: '+12345678901' }); log(test); // This update will apply using $set for the name let notover = await Test.findOneAndUpdate( { _id: test._id }, { name: 'Bill S. Preston' }, { new: true } ); log(notover); // This update will just use the supplied object, and overwrite let updated = await Test.findOneAndUpdate( { _id: test._id }, { name: 'Dan Smith' }, { new: true, overwrite: true } ); log(updated); } catch (e) { console.error(e); } finally { mongoose.disconnect(); } })() 

生产:

 Mongoose: tests.remove({}, {}) Mongoose: tests.insert({ name: 'john doe', phone: '+12345678901', _id: ObjectId("596efb0ec941ff0ec319ac1e"), __v: 0 }) { "__v": 0, "name": "john doe", "phone": "+12345678901", "_id": "596efb0ec941ff0ec319ac1e" } Mongoose: tests.findAndModify({ _id: ObjectId("596efb0ec941ff0ec319ac1e") }, [], { '$set': { name: 'Bill S. Preston' } }, { new: true, upsert: false, remove: false, fields: {} }) { "_id": "596efb0ec941ff0ec319ac1e", "name": "Bill S. Preston", "phone": "+12345678901", "__v": 0 } Mongoose: tests.findAndModify({ _id: ObjectId("596efb0ec941ff0ec319ac1e") }, [], { name: 'Dan Smith' }, { new: true, overwrite: true, upsert: false, remove: false, fields: {} }) { "_id": "596efb0ec941ff0ec319ac1e", "name": "Dan Smith" } 

显示文档被“覆盖”,因为我们抑制了否则将被内插的$set操作。 这两个示例首先显示没有overwrite选项,其中应用了$set修饰符,然后是“with” overwrite选项,其中您传入的用于“更新”的对象被尊重,并且不应用这样的$set修饰符。

请注意,这是MongoDB节点驱动程序如何“默认”执行此操作。 所以在“隐式” $set中添加的行为是由mongoose完成的,除非你不告诉它。

你可以传递upsert选项,它会replace文件:

 var collection = db.collection('test'); collection.findOneAndUpdate( {'_id': 'some_mongodb_id'}, {name: 'Dan smith Only'}, {upsert: true}, function (err, doc) { console.log(doc); } ); 

但这里的问题 – 是在callback文件是find文件,但没有更新。 因此,你需要执行这样的事情:

 var collection = db.collection('test'); collection.update( {'_id': 'some_mongodb_id'}, {name: 'Dan smith Only'}, {upsert: true}, function (err, doc) { collection.findOne({'_id': 'some_mongodb_id'}, function (err, doc) { console.log(doc); }); } );