Eigenlijk, maar voor het feit dat mangoest eigenlijk "rotzooit" met de update onder de dekens, is dit eigenlijk de standaardactie van je onderwerping aan een reguliere MongoDB-functie.
Dus mangoest vindt het "verstandig" als een gemakkelijke methode om te "veronderstellen" dat je een $set
wilde uitgeven instructie hier. Aangezien je dat in dit geval eigenlijk niet wilt, zet je dat gedrag uit via { overwrite: true }
in de opties doorgegeven aan een .update()
methode:
Als volledig voorbeeld:
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();
}
})()
Produceert:
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"
}
De weergave van het document is "overschreven" omdat we de $set
. hebben onderdrukt bewerking die anders geïnterpoleerd zou zijn. De twee voorbeelden worden eerst weergegeven zonder de overwrite
optie, die de $set
. toepast modifier, en dan "met" de overwrite
optie, waarbij het object dat je hebt doorgegeven voor de "update" wordt gerespecteerd en niet zo'n $set
modifier is toegepast.
Let op, dit is hoe het MongoDB Node-stuurprogramma dit "standaard" doet. Dus het gedrag van het toevoegen in de "impliciete" $set
wordt gedaan door mangoest, tenzij je zegt dat het niet moet.
OPMERKING De echte manier om te "vervangen" zou eigenlijk zijn om
replaceOne
. te gebruiken , ofwel als de API-methode vanreplaceOne()
of viabulkWrite()
. Deoverwrite
is een erfenis van hoe mangoest$set
wil toepassen zoals hierboven beschreven en gedemonstreerd, maar de MongoDB officiële API introduceertreplaceOne
als een "special" koning vanupdate()
bewerking die niet toestaat het gebruik van atomaire operatoren zoals$set
binnen de instructie en zal een foutmelding geven als je het probeert.Dit is semantisch veel duidelijker sinds vervangen leest heel duidelijk waar de methode eigenlijk voor wordt gebruikt. Binnen standaard API-aanroepen naar de
update()
varianten laten je natuurlijk nog steeds de atomaire operatoren weglaten en zullen gewoon vervangen inhoud toch. Maar waarschuwingen zijn te verwachten.