Bạn không thể tham chiếu đến các giá trị của tài liệu bạn muốn cập nhật, vì vậy bạn sẽ cần một truy vấn để truy xuất tài liệu và một truy vấn khác để cập nhật nó. Có vẻ như có một yêu cầu tính năng
cho điều đó trong OPEN
trạng thái từ năm 2016.
Nếu bạn có một bộ sưu tập với các tài liệu giống như sau:
{ "_id" : ObjectId("590a4aa8ff1809c94801ecd0"), "name" : "bar" }
Sử dụng trình bao MongoDB, bạn có thể làm như sau:
db.test.find({ name: "bar" }).snapshot().forEach((doc) => {
doc.name = "foo-" + doc.name;
db.test.save(doc);
});
Tài liệu sẽ được cập nhật như mong đợi:
{ "_id" : ObjectId("590a4aa8ff1809c94801ecd0"), "name": "foo-bar" }
Lưu ý .snapshot()
call.Điều này đảm bảo rằng truy vấn sẽ không trả về một tài liệu nhiều lần vì thao tác ghi can thiệp sẽ di chuyển nó do kích thước tài liệu tăng lên.
Áp dụng điều này cho ví dụ Mongoose của bạn, như được giải thích trong ví dụ chính thức này :
Cat.findById(1, (err, cat) => {
if (err) return handleError(err);
cat.name = cat.name + "bar";
cat.save((err, updatedCat) => {
if (err) return handleError(err);
...
});
});
Điều đáng nói là có một $concat
trong khuôn khổ tổng hợp, nhưng rất tiếc, bạn không thể sử dụng toán tử đó trong update
truy vấn.
Dù sao, tùy thuộc vào những gì bạn cần làm, bạn có thể sử dụng nó cùng với $out
toán tử để lưu kết quả của tổng hợp vào một tập hợp mới.
Với cùng một ví dụ đó, bạn sẽ làm:
db.test.aggregate([{
$match: { name: "bar" }
}, {
$project: { name: { $concat: ["foo", "-", "$name"] }}
}, {
$out: "prefixedTest"
}]);
Và một bộ sưu tập mới prefixedTest
sẽ được tạo bằng các tài liệu giống như sau:
{ "_id" : ObjectId("XXX"), "name": "foo-bar" }
Chỉ để tham khảo, có một câu hỏi thú vị khác về cùng chủ đề này với một vài câu trả lời đáng đọc: Cập nhật trường MongoDB bằng cách sử dụng giá trị của trường khác