Điều này thực sự yêu cầu câu lệnh cập nhật "hai" (hoặc "ba" với cảnh báo bổ sung) và là một trong những lý do rất tốt tại sao hoạt động "Hàng loạt" tồn tại.
db.collection.bulkWrite([
// Attempt to update the matched element
{ "updateOne": {
"filter": {
"name": "SweetTown",
"residents.name": "Bob"
},
"update": {
"$set": { "residents.$.reputation": 30 }
}
},
// $push the element where not matched
{ "updateOne": {
"filter": {
"name": "SweetTown",
"residents.name": { "$ne": "Bob" }
},
"update": {
"$push": {
"residents": { "name": "Bob", "reputation": 30 }
}
}
}}
])
Hoặc nếu bạn thực sự muốn bao gồm một "upsert"
cho tài liệu cơ bản của "SweetTown"
thì bạn cần tách mối quan tâm đó ra thành bài kiểm tra của riêng nó:
db.collection.bulkWrite([
// Attempt to update the matched element
{ "updateOne": {
"filter": {
"name": "SweetTown",
"residents.name": "Bob"
},
"update": {
"$set": { "residents.$.reputation": 30 }
}
},
// $push the element where not matched
{ "updateOne": {
"filter": {
"name": "SweetTown",
"residents.name": { "$ne": "Bob" }
},
"update": {
"$push": {
"residents": { "name": "Bob", "reputation": 30 }
}
}
}},
// Only use $setOnInsert when actually an upsert
{ "updateOne": {
"filter": {
"name": "SweetTown"
},
"update": {
"$setOnInsert": {
"residents": [{ "name": "Bob", "reputation": 30 }]
}
},
"upsert": true
}}
])
Vì vậy, khái niệm chung là chỉ áp dụng $setOnInsert
hành động khi "upsert"
thực sự xảy ra. Để đảm bảo điều này chỉ xảy ra trong trường hợp này, các thao tác khác thực sự xem xét phần tử mảng không được đánh dấu bằng "upsert"
quyền mua. Phần đó có mục đích.
Dù bạn nhìn nhận nó theo cách nào, thì điều đó chỉ có thể xảy ra đối với một trong số các hoạt động đó để thực sự thực hiện bất kỳ sửa đổi nào trong cơ sở dữ liệu, vì phần tử được tìm thấy hoặc không, hoặc thậm chí không tìm thấy tài liệu và một tài liệu mới được tạo.
Không có trường hợp nào có thể thực hiện loại hoạt động đó trong một câu lệnh cập nhật duy nhất. Tuy nhiên, vì hoạt động "Hàng loạt" chỉ thực sự là một yêu cầu với một phản hồi, sau đó theo như ứng dụng của bạn có liên quan thì nó chỉ cần nói chuyện với máy chủ một lần yêu cầu máy chủ thử tất cả ba điều này và trả lại phản hồi.
Để sử dụng sớm hơn Bulk API trực tiếp, thì cú pháp thay thế là:
var bulk = db.collection.initializeOrderedBulkOp();
// $set matched where existing
bulk.find({ "name": "SweetTown", "residents.name": "Bob" }).updateOne({
"$set": { "residents.$.reputation": 30 }
});
// $push where not existing
bulk.find({ "name": "SweetTown", "residents.name": { "$ne": "Bob" } }).updateOne({
"$push": { "residents": { "name": "Bob", "reputation": 30 } }
});
// Attempt to upsert only
bulk.find({ "name": "SweetTown" }).upsert().updateOne({
"$setOnInsert": {
"residents": [{ "name": "Bob", "reputation": 30 }]
}
})
bulk.execute();