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()
. Leoverwrite
est un héritage de la façon dont la mangouste veut appliquer$set
comme décrit et démontré ci-dessus, cependant l'API officielle de MongoDB introduitreplaceOne
en tant que "spécial" roi deupdate()
opération qui ne permet pas l'utilisation d'opérateurs atomiques comme$set
dans 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.