Всъщност, с изключение на факта, че mongoose всъщност "забърква" с актуализацията под завивките, това всъщност е действието по подразбиране при изпращането ви на обикновена функция на MongoDB.
Така че mongoose смята, че е "мъдро" като удобен метод да "предполагаме", че сте имали предвид да издадете $set
инструкция тук. Тъй като всъщност не искате да правите това в този случай, изключвате това поведение чрез { overwrite: true }
в опциите, предадени на всеки .update()
метод:
Като пълен пример:
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();
}
})()
Произвежда:
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"
}
Показването на документа е "презаписано", защото потиснахме $set
операция, която иначе би била интерполирана. Двете проби се показват първи без overwrite
опция, която прилага $set
модификатор, а след това "с" overwrite
опция, където обектът, който сте предали за "актуализация", се спазва и няма такъв $set
се прилага модификатор.
Забележете, така драйверът на MongoDB Node прави това "по подразбиране". Така че поведението на добавяне в "неявния" $set
се извършва от мангуста, освен ако не му кажете да не го прави.
ЗАБЕЛЕЖКА Истинският начин за „замяна“ всъщност би бил да използвате
replaceOne
, или като API метод наreplaceOne()
или чрезbulkWrite()
.overwrite
е наследство на начина, по който mongoose иска да приложи$set
както е описано и демонстрирано по-горе, обаче официалният API на MongoDB въвеждаreplaceOne
като „специален“ крал наupdate()
операция, коятоне позволявата използването на атомни оператори като$set
в изявлението и ще грешка, ако опитате.Това е много по-ясно семантично, тъй като замени чете много ясно за какво всъщност се използва методът. В рамките на стандартните API извиквания към
update()
вариантите, разбира се, все още ви позволяват да пропуснете атомните оператори и просто ще заменят съдържание така или иначе. Но трябва да се очакват предупреждения.