Trên thực tế, nhưng thực tế là mongoose đang thực sự "gây rối" với bản cập nhật dưới vỏ bọc, đây thực sự là hành động mặc định khi bạn gửi một hàm MongoDB thông thường.
Vì vậy mongoose cho rằng nó "khôn ngoan" như một phương pháp tiện lợi để "đoán trước" bạn định phát hành $set
hướng dẫn ở đây. Vì bạn thực sự không muốn làm điều đó trong trường hợp này, bạn tắt hành vi đó thông qua { overwrite: true }
trong các tùy chọn được chuyển đến bất kỳ .update()
nào phương pháp:
Như một ví dụ đầy đủ:
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();
}
})()
Sản xuất:
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"
}
Việc hiển thị tài liệu bị "ghi đè" vì chúng tôi đã chặn $set
hoạt động mà nếu không sẽ được nội suy. Hai mẫu hiển thị đầu tiên mà không có overwrite
, áp dụng $set
sửa đổi, và sau đó "với" overwrite
tùy chọn, trong đó đối tượng bạn đã chuyển vào cho "bản cập nhật" được tôn trọng và không có $set
nào như vậy công cụ sửa đổi được áp dụng.
Lưu ý, đây là cách trình điều khiển MongoDB Node thực hiện điều này "theo mặc định". Vì vậy, hành vi thêm vào $set
"ngầm định" đang được thực hiện bởi mongoose, trừ khi bạn yêu cầu nó không làm như vậy.
LƯU Ý Cách thực sự để "thay thế" thực sự sẽ là sử dụng
replaceOne
, hoặc là phương thức API củareplaceOne()
hoặc thông quabulkWrite()
.overwrite
là di sản của cách mongoose muốn áp dụng$set
như được mô tả và trình bày ở trên, tuy nhiên API chính thức của MongoDB giới thiệureplaceOne
như một "đặc biệt" vua củaupdate()
hoạt động mà không cho phép việc sử dụng các toán tử nguyên tử như$set
trong câu lệnh và sẽ lỗi nếu bạn thử.Điều này rõ ràng hơn nhiều về mặt ngữ nghĩa kể từ khi thay thế đọc rất rõ ràng phương pháp này thực sự được sử dụng để làm gì. Trong các lệnh gọi API tiêu chuẩn tới
update()
tất nhiên, các biến thể vẫn cho phép bạn bỏ qua các toán tử nguyên tử và sẽ chỉ thay thế nội dung nào. Nhưng cần có cảnh báo.