Về cơ bản, bạn có 3 trường hợp:
- cả sách và bài đánh giá đều tồn tại. Đây là một
$set
đơn giản - sách tồn tại nhưng không phải là bài đánh giá. Điều này cần một
$push
- sách không tồn tại. Điều này cần
{upsert:1}
và một$setOnInsert
Tôi không thể tìm ra cách hợp nhất bất kỳ hai trong số này mà không ảnh hưởng đến tính toàn vẹn của dữ liệu trong trường hợp thất bại (hãy nhớ rằng MongoDB không có giao dịch nguyên tử).
So my ý tưởng tốt nhất là như sau:
// Case 1:
db.books.update({isbn:'1234567890',
review: { $elemMatch: {userID: '01234'}}},
{$set: {'review.$.rating': NEW_RATING}}
)
// Case 2:
db.books.update({isbn:'1234567890',
review: { $not: { $elemMatch: {userID: '01234'}}}},
{$push: {review: {rating: NEW_RATING, userID:'01234'}}}
)
// Case 3:
db.books.update({isbn:'1234567890'},
{$setOnInsert: {review: [{rating: NEW_RATING, userID:'01234'}]}},
{upsert:1}
)
Bạn có thể chạy một cách mù quáng ba bản cập nhật đó ở dạng thô vì không có trường hợp chồng chéo nào giữa chúng. Vẻ đẹp của điều này là tất cả các hoạt động này đều idempotent
. Vì vậy, bạn có thể áp dụng chúng một lần hoặc nhiều lần và luôn nhận được kết quả tương tự. Điều này đặc biệt quan trọng trong trường hợp chuyển đổi dự phòng. Ngoài ra, không có cách nào để DB của bạn không nhất quán hoặc lỏng lẻo hiện có dữ liệu trong trường hợp bị lỗi. Tệ nhất, bài đánh giá là không đã cập nhật. Cuối cùng điều này nên đảm bảo tính nhất quán của dữ liệu ngay cả trong trường hợp cập nhật đồng thời (nghĩa là:trong trường hợp đó, một bản cập nhật sẽ ghi đè lên bản còn lại, nhưng bạn không nên có hai tài liệu cho cùng một cuốn sách hoặc hai bài đánh giá của cùng một người dùng cho cùng một cuốn sách).
Điểm sau đó phải được xác nhận vì ở đây đã muộn nên phân tích của tôi có thể hơi nghi ngờ.
Lưu ý cuối cùng, nếu bạn muốn giảm số lượng chuyến đi khứ hồi giữa MongoDB và ứng dụng của mình, bạn có thể xem update
lệnh cơ sở dữ liệu
cho phép bạn kết hợp nhiều bản cập nhật trong một lệnh.