Faktisk, men for det faktum, at mongoose faktisk "roder med" opdateringen under dynen, er dette faktisk standardhandlingen for din indsendelse til en almindelig MongoDB-funktion.
Så mongoose anser det for "klogt" som en bekvem metode at "formode", at du havde tænkt dig at udstede et $set
instruktion her. Da du faktisk ikke ønsker at gøre det i dette tilfælde, slår du den adfærd fra via { overwrite: true }
i de muligheder, der er videregivet til enhver .update()
metode:
Som et fuldstændigt eksempel:
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();
}
})()
Producerer:
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"
}
Visning af dokumentet er "overskrevet", fordi vi har undertrykt $set
operation, der ellers ville være blevet interpoleret. De to eksempler vises først uden overwrite
mulighed, som anvender $set
modifikator, og derefter "med" overwrite
mulighed, hvor det objekt, du sendte til "opdateringen" respekteres, og ingen sådan $set
modifikator anvendes.
Bemærk, det er sådan MongoDB Node-driveren gør dette "som standard". Altså adfærden med at tilføje det "implicitte" $set
bliver gjort af mongoose, medmindre du fortæller det ikke.
BEMÆRK Den sande måde at "erstatte" på ville faktisk være at bruge replaceOne
, enten som API-metoden for replaceOne()
eller gennem bulkWrite()
. overwrite
er en arv af, hvordan mongoose ønsker at anvende $set
som beskrevet og demonstreret ovenfor, men MongoDB's officielle API introducerer replaceOne
som en "særlig" konge af update()
operation, som ikke tillader brugen af atomoperatorer som $set
i sætningen og vil fejle, hvis du prøver.
Dette er meget tydeligere semantisk siden erstat læser meget tydeligt på, hvad metoden egentlig bruges til. Inden for standard API-kald til update()
varianter giver dig selvfølgelig stadig mulighed for at udelade atomoperatorerne og vil bare erstatte indhold alligevel. Men advarsler bør forventes.