2017-07-19 55 views
2

说,我有一个文件:

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

我要更新这个文件:

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

而且结果应该是这样的:

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

应该删除未指定的属性。

我该怎么做?

+0

您是否尝试使用更新函数(而不是findOneAndUpdate)? –

+0

@ israel.zinc我有,没有区别 – stkvtflw

+0

@ israel.zinc它不会有所作为。这是通过在[更新对象]中添加['$ set'](https://docs.mongodb.com/manual/reference/operator/update/set/)来做到这一点的“猫鼬”,标准驱动程序只需要通过“按原样”传递该对象。所以这种行为需要为猫鼬“关闭”,以便使它像你实际要求的那样工作。 –

回答

3

实际上,实际上,猫鼬实际上是在“掩盖”更新下的事实,这实际上是您提交给常规MongoDB函数的默认操作。

因此,猫鼬认为它是“明智的”,作为一种方便的方法来“假设”你在这里发布$set指令。

作为一个完整的例子:

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

})() 

产地:

因为你其实并不想这样做,在这种情况下,你传递给任何 .update()方法的选项通过 { overwrite: true }关闭该行为
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选项,其中您传入“更新”的对象受到尊重,并且没有应用此修饰符。

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

+0

非常感谢,这个覆盖功能完全没有记录:-( –

0

你可以通过upsert选项,它将替换文件:这里

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

但问题 - 是doc在回调中找到文档,但不能更新。 因此,您需要执行如下操作:

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