En fait, mais pour le fait que la mangouste est en train de "déconner" la mise à jour sous les couvertures, c'est en fait l'action par défaut de votre soumission à une fonction MongoDB régulière.
Donc, mangouste juge "sage" comme méthode pratique de "présumer" que vous vouliez émettre un $set instruction ici. Puisque vous ne voulez pas faire cela dans ce cas, vous désactivez ce comportement via { overwrite: true } dans les options passées à n'importe quel .update() méthode :
À titre d'exemple complet :
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();
}
})()
Produit :
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"
}
Montrer que le document est "écrasé" car nous avons supprimé le $set opération qui, autrement, aurait été interpolée. Les deux exemples s'affichent en premier sans le overwrite option, qui applique le $set modificateur, puis "avec" le overwrite option, où l'objet que vous avez passé pour la "mise à jour" est respecté et aucun $set modificateur est appliqué.
Notez que c'est ainsi que le pilote MongoDB Node le fait "par défaut". Ainsi, le comportement d'ajout dans le $set "implicite" est fait par la mangouste, sauf si vous lui dites de ne pas le faire.
REMARQUE La vraie façon de "remplacer" serait en fait d'utiliser
replaceOne, soit comme méthode API dereplaceOne()ou viabulkWrite(). Leoverwriteest un héritage de la façon dont la mangouste veut appliquer$setcomme décrit et démontré ci-dessus, cependant l'API officielle de MongoDB introduitreplaceOneen tant que "spécial" roi deupdate()opération qui ne permet pas l'utilisation d'opérateurs atomiques comme$setdans la déclaration et vous obtiendrez une erreur si vous essayez.C'est beaucoup plus clair sémantiquement puisque remplacer indique très clairement à quoi sert réellement la méthode. Dans les appels d'API standard à
update()les variantes vous permettent bien sûr toujours d'omettre les opérateurs atomiques et ne feront que remplacer contenu de toute façon. Mais il faut s'attendre à des avertissements.