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

Cập nhật Mảng lồng nhau với MongoDB

Phạm vi chung và giải thích

Có một số điều sai với những gì bạn đang làm ở đây. Trước hết điều kiện truy vấn của bạn. Bạn đang đề cập đến một số _id các giá trị mà bạn không cần phải làm và ít nhất một trong số đó không phải ở cấp cao nhất.

Để nhận được một giá trị "lồng nhau" và cũng giả định rằng _id giá trị là duy nhất và sẽ không xuất hiện trong bất kỳ tài liệu nào khác, biểu mẫu truy vấn của bạn phải như thế này:

Model.update(
    { "array1.array2._id": "123" },
    { "$push": { "array1.0.array2.$.answeredBy": "success" } },
    function(err,numAffected) {
       // something with the result in here
    }
);

Bây giờ điều đó thực sự sẽ hoạt động, nhưng thực sự chỉ là một điều may mắn khi nó làm được vì có những lý do rất chính đáng khiến nó không hoạt động với bạn.

Bài đọc quan trọng có trong tài liệu chính thức cho $ vị trí toán tử dưới chủ đề "Mảng lồng nhau". Điều này nói lên điều gì:

Toán tử vị trí $ không thể được sử dụng cho các truy vấn đi qua nhiều hơn một mảng, chẳng hạn như truy vấn đi qua các mảng được lồng trong các mảng khác, bởi vì sự thay thế cho $ placeholder là một giá trị duy nhất

Cụ thể điều đó có nghĩa là phần tử sẽ được so khớp và trả về trong trình giữ chỗ vị trí là giá trị của chỉ mục từ đầu tiên mảng phù hợp. Điều này có nghĩa là trong trường hợp của bạn, chỉ mục phù hợp trên mảng cấp "cao nhất".

Vì vậy, nếu bạn nhìn vào ký hiệu truy vấn như được hiển thị, chúng tôi đã "mã hóa cứng" đầu tiên (hoặc 0 chỉ mục) trong mảng cấp cao nhất và điều đó xảy ra khi phần tử phù hợp trong "array2" cũng là mục nhập chỉ mục bằng không.

Để chứng minh điều này, bạn có thể thay đổi _id phù hợp giá trị thành "124" và kết quả sẽ $push một mục nhập mới vào phần tử có _id "123" vì chúng đều nằm trong mục nhập chỉ mục 0 của "array1" và đó là giá trị được trả về trình giữ chỗ.

Vì vậy, đó là vấn đề chung với các mảng lồng nhau. Bạn có thể xóa một trong các cấp và bạn vẫn có thể $push đến đúng phần tử trong mảng "trên cùng" của bạn, nhưng vẫn sẽ có nhiều cấp.

Cố gắng tránh lồng ghép các mảng vì bạn sẽ gặp phải sự cố cập nhật như được hiển thị.

Trường hợp chung là "san bằng" những thứ bạn "nghĩ" là "cấp độ" và thực sự làm cho luận điểm thành "thuộc tính" trên các mục chi tiết cuối cùng. Ví dụ:dạng "phẳng" của cấu trúc trong câu hỏi phải là:

 {
   "answers": [
     { "by": "success", "type2": "123", "type1": "12" }
   ]
 }

Hoặc ngay cả khi chấp nhận mảng bên trong là $push duy nhất và không bao giờ được cập nhật:

 {
   "array": [
     { "type1": "12", "type2": "123", "answeredBy": ["success"] },
     { "type1": "12", "type2": "124", "answeredBy": [] }
   ]
 }

Cả hai đều cho vay các bản cập nhật nguyên tử trong phạm vi của $ vị trí nhà điều hành

MongoDB 3.6 trở lên

Từ MongoDB 3.6 có sẵn các tính năng mới để hoạt động với các mảng lồng nhau. Điều này sử dụng $[<identifier>] được lọc theo vị trí cú pháp để khớp với các phần tử cụ thể và áp dụng các điều kiện khác nhau thông qua arrayFilters trong tuyên bố cập nhật:

Model.update(
  {
    "_id": 1,
    "array1": {
      "$elemMatch": {
        "_id": "12","array2._id": "123"
      }
    }
  },
  {
    "$push": { "array1.$[outer].array2.$[inner].answeredBy": "success" }
  },
  {
    "arrayFilters": [{ "outer._id": "12" },{ "inner._id": "123" }] 
  }
)

"arrayFilters" như được chuyển đến các tùy chọn cho .update() hoặc thậm chí .updateOne() , .updateMany() , .findOneAndUpdate() hoặc .bulkWrite() phương thức chỉ định các điều kiện để khớp với số nhận dạng được đưa ra trong câu lệnh cập nhật. Bất kỳ phần tử nào phù hợp với điều kiện đã cho sẽ được cập nhật.

Bởi vì cấu trúc là "lồng nhau", chúng tôi thực sự sử dụng "nhiều bộ lọc" như được chỉ định với một "mảng" định nghĩa bộ lọc như được hiển thị. "Giá trị nhận dạng" được đánh dấu được sử dụng để đối sánh với $[<identifier>] được lọc theo vị trí cú pháp thực sự được sử dụng trong khối cập nhật của câu lệnh. Trong trường hợp này innerouter là các số nhận dạng được sử dụng cho từng điều kiện như được chỉ định với chuỗi lồng nhau.

Bản mở rộng mới này giúp cập nhật nội dung mảng lồng nhau có thể thực hiện được, nhưng nó không thực sự giúp ích cho việc "truy vấn" dữ liệu như vậy, vì vậy các lưu ý tương tự cũng được áp dụng như đã giải thích trước đó.

Bạn thường thực sự "có ý" thể hiện dưới dạng "thuộc tính", ngay cả khi bộ não của bạn ban đầu nghĩ là "lồng vào nhau", thì đó thường chỉ là phản ứng đối với cách bạn tin rằng "các phần quan hệ trước đó" kết hợp với nhau. Trong thực tế, bạn thực sự cần chuẩn hóa nhiều hơn.

Ngoài ra, hãy xem Cách cập nhật nhiều phần tử mảng trong mongodb, vì các toán tử cập nhật mới này thực sự khớp và cập nhật "nhiều phần tử mảng" thay vì chỉ đầu tiên , là hành động trước đây của các cập nhật vị trí.

LƯU Ý Hơi trớ trêu, vì điều này được chỉ định trong đối số "tùy chọn" cho .update() và giống như các phương pháp, cú pháp nói chung tương thích với tất cả các phiên bản trình điều khiển phát hành gần đây.

Tuy nhiên, điều này không đúng với mongo shell, vì cách phương thức được triển khai ở đó ("trớ trêu thay cho khả năng tương thích ngược") arrayFilters đối số không được công nhận và bị loại bỏ bởi một phương pháp nội bộ phân tích cú pháp các tùy chọn để cung cấp "khả năng tương thích ngược" với các phiên bản máy chủ MongoDB trước đó và "kế thừa" .update() Cú pháp gọi API.

Vì vậy, nếu bạn muốn sử dụng lệnh trong mongo shell hoặc các sản phẩm "dựa trên shell" khác (đặc biệt là Robo 3T), bạn cần có phiên bản mới nhất từ ​​nhánh phát triển hoặc phiên bản sản xuất từ ​​3.6 trở lên.

Xem thêm positional all $[] cũng cập nhật "nhiều phần tử mảng" nhưng không áp dụng cho các điều kiện đã chỉ định và áp dụng cho tất cả các phần tử trong mảng mà đó là hành động mong muốn.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Sự cố khi chạy ví dụ trong Meteor

  2. Tầm quan trọng ngày càng tăng của MongoDB trong lĩnh vực khoa học dữ liệu

  3. Giới thiệu về kiểu dữ liệu MongoDB

  4. Loạt bài phân tích MongoDB:SlamData - Chạy SQL &tạo báo cáo trực tiếp trên MongoDB

  5. Làm cách nào để truy vấn mongodb bằng cách sử dụng mongoid / rails mà không hết thời gian?