Na verdade, mas pelo fato de que o mangusto está realmente "mexendo" com a atualização nos bastidores, essa é realmente a ação padrão do seu envio para uma função regular do MongoDB.
Portanto, o mangusto considera "sábio" como um método de conveniência "presumir" que você pretendia emitir um
$set
instrução aqui. Como você realmente não deseja fazer isso neste caso, desative esse comportamento por meio de { overwrite: true }
nas opções passadas para qualquer .update()
método:Como um exemplo completo:
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();
}
})()
Produz:
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"
}
Mostrar que o documento foi "substituído" porque suprimimos o
$set
operação que de outra forma teria sido interpolada. Os dois exemplos são exibidos primeiro sem o overwrite
opção, que aplica o $set
modificador e, em seguida, "com" o overwrite
opção, onde o objeto que você passou para a "atualização" é respeitado e nenhum $set
modificador é aplicado. Observe que é assim que o driver do MongoDB Node faz isso "por padrão". Portanto, o comportamento de adicionar no
$set
"implícito" está sendo feito pelo mangusto, a menos que você diga que não.
OBSERVAÇÃO A verdadeira maneira de "substituir" seria usarreplaceOne
, seja como o método de API dereplaceOne()
ou através debulkWrite()
. Ooverwrite
é um legado de como o mangusto quer aplicar$set
conforme descrito e demonstrado acima, no entanto, a API oficial do MongoDB apresentareplaceOne
como "especial" rei deupdate()
operação que não permite o uso de operadores atômicos como$set
dentro da instrução e dará erro se você tentar.
Isso é muito mais claro semanticamente desde substituir lê muito claramente para que o método é realmente usado. Dentro de chamadas de API padrão para oupdate()
variantes, é claro, ainda permitem que você omita os operadores atômicos e apenas substituir conteúdo de qualquer maneira. Mas os avisos devem ser esperados.