MongoDB
 sql >> Cơ Sở Dữ Liệu >  >> NoSQL >> MongoDB

mongodb $ addToSet vào một trường không phải là mảng khi cập nhật trên upert

Những gì bạn đang cố gắng làm ở đây là thêm một mục mới vào một mảng chỉ nơi mục đó không tồn tại và cũng tạo một tài liệu mới nơi nó không tồn tại. Bạn chọn $addToSet bởi vì bạn muốn các mục là duy nhất, nhưng trên thực tế, bạn thực sự muốn chúng là duy nhất chỉ bằng "a".

Vì vậy, $addToset sẽ không làm điều đó, và bạn cần phải "kiểm tra" phần tử đang có mặt. Nhưng vấn đề thực sự ở đây là không thể vừa làm vừa “up” cùng một lúc. Logic không thể hoạt động vì một tài liệu mới sẽ được tạo bất cứ khi nào không tìm thấy phần tử mảng, thay vì nối vào phần tử mảng như bạn muốn.

Các lỗi hoạt động hiện tại theo thiết kế là $addToSet không thể được sử dụng để "tạo" một mảng, mà chỉ để "thêm" các thành viên vào một mảng hiện có. Nhưng như đã nêu, bạn gặp các vấn đề khác với việc đạt được logic.

Những gì bạn cần ở đây là một chuỗi các hoạt động cập nhật mà mỗi "cố gắng" thực hiện hành động mong đợi của họ. Điều này chỉ có thể được thực hiện với nhiều câu lệnh:

// attempt "upsert" where document does not exist
// do not alter the document if this is an update
db.test.update(
    { "name": "abc" },
    { "$setOnInsert": { "config": [{ "a": 1, "b": 2 }] }},
    { "upsert": true }
)

// $push the element where "a": 1 does not exist
db.test.update(
    { "name": "abc", "config.a": { "$ne": 1 } },
    { "$push": { "config": { "a": 1, "b": 2 } }}
)

// $set the element where "a": 1 does exist
db.test.update(
    { "name": "abc", "config.a": 1 },
    { "$set": { "config.$.b": 2 } }
)

Trong lần lặp đầu tiên, câu lệnh đầu tiên sẽ "nâng cấp" tài liệu và tạo mảng với các mục. Câu lệnh thứ hai sẽ không khớp với tài liệu vì phần tử "a" có giá trị đã được chỉ định. Câu lệnh thứ ba sẽ khớp với tài liệu nhưng nó sẽ không thay đổi tài liệu trong thao tác ghi vì các giá trị không thay đổi.

Nếu bây giờ bạn thay đổi đầu vào thành "b": 3 bạn nhận được các phản hồi khác nhau nhưng kết quả mong muốn:

db.test.update(
    { "name": "abc" },
    { "$setOnInsert": { "config": [{ "a": 1, "b": 3 }] }},
    { "upsert": true }
)

db.test.update(
    { "name": "abc", "config.a": { "$ne": 1 } },
    { "$push": { "config": { "a": 1, "b": 3 } }}
)

db.test.update(
    { "name": "abc", "config.a": 1 },
    { "$set": { "config.$.b": 3 } }
)

Vì vậy, bây giờ câu lệnh đầu tiên khớp với một tài liệu có "name": "abc" nhưng không làm bất cứ điều gì vì các hoạt động hợp lệ duy nhất là trên "insert". Câu lệnh thứ hai không khớp vì "a" phù hợp với điều kiện. Trạng thái thứ ba khớp với giá trị của "a" và thay đổi "b" trong phần tử đã so khớp thành giá trị mong muốn.

Sau đó, việc thay đổi "a" thành một giá trị khác không tồn tại trong mảng cho phép cả 1 và 3 không làm gì cả nhưng câu lệnh thứ hai thêm một thành viên khác vào mảng giữ nội dung duy nhất bằng các khóa "a" của chúng.

Ngoài ra, việc gửi một báo cáo không có thay đổi nào so với dữ liệu hiện có, tất nhiên sẽ dẫn đến phản hồi cho biết không có gì thay đổi trên tất cả các tài khoản.

Đó là cách bạn thực hiện các hoạt động của mình. Bạn có thể thực hiện việc này với "đã đặt hàng" Bulk hoạt động sao cho chỉ có một yêu cầu và phản hồi duy nhất từ ​​máy chủ với phản hồi hợp lệ để sửa đổi hoặc tạo.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Lập chỉ mục Mongo trên đối tượng lồng nhau

  2. Truy vấn khác biệt với MongoMapper

  3. Làm cách nào để lấy lại giá trị mới sau khi cập nhật trong một mảng được nhúng?

  4. Nhúng lược đồ đang gây ra lỗi

  5. Truy xuất khóa MongoDB cụ thể từ DuplicateKeyException thực sự đã được sao chép (Java / Spring)