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

Khớp điều kiện và ngày mới nhất từ ​​mảng

Khái niệm cơ bản ở đây là bạn cần khung tổng hợp để áp dụng các điều kiện để "lọc" các phần tử mảng theo các điều kiện. Tùy thuộc vào phiên bản có sẵn, có các kỹ thuật khác nhau có thể được áp dụng.

Trong mọi trường hợp, đây là kết quả:

{
    "_id" : ObjectId("593921425ccc8150f35e7664"),
    "user1" : 1,
    "user2" : 4,
    "messages" : {
            "sender" : 1,
            "datetime" : ISODate("2017-06-09T10:04:50Z"),
            "body" : "hiii 1"
    }
}
{
    "_id" : ObjectId("593921425ccc8150f35e7663"),
    "user1" : 1,
    "user2" : 3,
    "messages" : {
            "sender" : 1,
            "datetime" : ISODate("2017-06-10T10:04:50Z"),
            "body" : "hiii 2"
    }
}
{
    "_id" : ObjectId("593921425ccc8150f35e7662"),
    "user1" : 1,
    "user2" : 2,
    "messages" : {
            "sender" : 1,
            "datetime" : ISODate("2017-06-08T10:04:50Z"),
            "body" : "hiii 0"
    }
}

MongoDB 3.4 trở lên

db.chat.aggregate([
  { "$match": { "messages.sender": 1 } },
  { "$replaceRoot": {
    "newRoot": {
      "$let": {
        "vars": {
          "messages": {
            "$filter": {
              "input": "$messages",
              "as": "m",
              "cond": { "$eq": [ "$$m.sender", 1 ] }
            }
          },
          "maxDate": {
            "$max": {
              "$map": {
                "input": {
                  "$filter": {
                    "input": "$messages",
                    "as": "m",
                    "cond": { "$eq": [ "$$m.sender", 1 ] }
                  }
                },
                "as": "m",
                "in": "$$m.datetime"
              }
            }
          }
        },
        "in": {
          "_id": "$_id",
          "user1": "$user1",
          "user2": "$user2",
          "messages": {
            "$arrayElemAt": [
              { "$filter": {
                "input": "$$messages",
                "as": "m",
                "cond": { "$eq": [ "$$m.datetime", "$$maxDate" ] }
              }},
              0
            ]
          }    
        }
      }
    }
  }}
])

Đây là cách hiệu quả nhất tận dụng lợi thế của $ ReplaceRoot cho phép chúng tôi khai báo các biến để sử dụng trong cấu trúc "được thay thế" bằng cách sử dụng $ let . Ưu điểm chính ở đây là điều này chỉ yêu cầu "hai" giai đoạn đường ống.

Để khớp với nội dung mảng, bạn sử dụng $ filter nơi bạn áp dụng $ eq hoạt động logic để kiểm tra giá trị của "sender" . Trong trường hợp điều kiện khớp, thì chỉ các mục nhập mảng phù hợp mới được trả về.

Sử dụng cùng một $ filter để chỉ các mục nhập "người gửi" phù hợp mới được xem xét, sau đó chúng tôi muốn áp dụng $ max qua danh sách "đã lọc" đến các giá trị trong "datetime" . $ max ] 5 giá trị là ngày "mới nhất" theo các điều kiện.

Chúng tôi muốn giá trị này để sau này chúng tôi có thể so sánh kết quả trả về từ mảng "đã lọc" với "ngày tối đa" này. Đó là những gì xảy ra bên trong "in" khối $ let trong đó hai "biến" được khai báo trước đó cho nội dung được lọc và "maxDate" lại được áp dụng cho $ filter để trả về giá trị phải là giá trị duy nhất đáp ứng cả hai điều kiện có "ngày mới nhất".

Vì bạn chỉ muốn "một" kết quả, chúng tôi sử dụng $ arrayElemAt để sử dụng giá trị thay vì mảng.

MongoDB 3.2

db.chat.aggregate([
  { "$match": { "messages.sender": 1 } },
  { "$project": {
    "user1": 1,
    "user2": 1,
    "messages": {
      "$filter": {
        "input": "$messages",
        "as": "m",
        "cond": { "$eq": [ "$$m.sender", 1 ] }
      }
    },
    "maxDate": {
      "$max": {
        "$map": {
          "input": {
            "$filter": {
              "input": "$messages",
              "as": "m",
              "cond": { "$eq": [ "$$m.sender", 1 ] }
            }
          },
          "as": "m",
          "in": "$$m.datetime"
        }
      }
    }         
  }},
  { "$project": {
    "user1": 1,
    "user2": 1,
    "messages": {
      "$arrayElemAt":[
       { "$filter": {
         "input": "$messages",
          "as": "m",
          "cond": { "$eq": [ "$$m.datetime", "$maxDate" ] }
       }},
       0
      ]
    }
  }}
])

Về cơ bản đây là quá trình giống như được mô tả, nhưng không có $ ReplaceRoot giai đoạn đường ống, chúng tôi cần áp dụng trong hai $ project các giai đoạn. Lý do cho điều này là chúng tôi cần "giá trị được tính toán" từ "maxDate" để thực hiện điều đó cuối cùng $ filter và nó không có sẵn để thực hiện trong một câu lệnh ghép, vì vậy thay vào đó chúng tôi chia các đường ống dẫn. Điều này có tác động nhỏ đến chi phí chung của hoạt động.

Trong MongoDB 2.6 đến 3.0, chúng tôi có thể sử dụng hầu hết các kỹ thuật ở đây ngoại trừ $ arrayElemAt và chấp nhận kết quả "mảng" với một mục nhập duy nhất hoặc đưa vào một $ thư giãn giai đoạn để đối phó với những gì bây giờ phải là một mục duy nhất.

MongoDB phiên bản trước

db.chat.aggregate([
  { "$match": { "messages.sender": 1 } },
  { "$unwind": "$messages" },
  { "$match": { "messages.sender": 1 } },
  { "$sort": { "_id": 1, "messages.datetime": -1 } },
  { "$group": {
    "_id": "$_id",
    "user1": { "$first": "$user1" },
    "user2": { "$first": "$user2" },
    "messages": { "$first": "$messages" }
  }}
])

Mặc dù có vẻ ngắn gọn, nhưng đây là hoạt động tốn kém nhất cho đến nay. Tại đây, bạn phải sử dụng $ unwind để áp dụng các điều kiện cho các phần tử của mảng. Đây là một quá trình rất tốn kém vì nó tạo ra một bản sao của mỗi tài liệu cho mỗi mục nhập mảng và về cơ bản được thay thế bằng các toán tử hiện đại để tránh điều này trong trường hợp "lọc".

$ khớp thứ hai ở đây giai đoạn loại bỏ bất kỳ phần tử nào (bây giờ là "tài liệu") không phù hợp với điều kiện "người gửi". Sau đó, chúng tôi áp dụng $ sort để đặt ngày "mới nhất" lên đầu mỗi tài liệu bằng _id , do đó có hai phím "sắp xếp".

Cuối cùng, chúng tôi áp dụng $ group để chỉ tham khảo tài liệu gốc, sử dụng $ 1 làm bộ tích lũy để lấy phần tử "ở trên cùng".




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Cách mongoexport với một trường

  2. Giám sát các phiên bản MongoDB bằng Dịch vụ Giám sát MongoDB (MMS)

  3. Truy vấn chỉ tìm kiếm MongoDB trong những giờ cụ thể

  4. Kết nối với vùng chứa của Docker Mongodb từ vùng chứa của docker khác

  5. Mongodb foreach cho bộ sưu tập lồng nhau để cập nhật / sao chép tài liệu sang bộ sưu tập khác