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

Nhiều điều kiện giới hạn trong mongodb

Nói chung những gì bạn đang mô tả là một câu hỏi tương đối phổ biến xung quanh cộng đồng MongoDB mà chúng tôi có thể mô tả là "top n kết quả vấn đề ". Đây là khi được cung cấp một số đầu vào có khả năng được sắp xếp theo một cách nào đó, cách lấy n hàng đầu kết quả mà không cần dựa vào các giá trị chỉ mục tùy ý trong dữ liệu.

MongoDB có $first toán tử khả dụng cho khung tổng hợp giải quyết phần "đầu tiên" của vấn đề, vì điều này thực sự lấy mục "đầu tiên" được tìm thấy trên ranh giới nhóm, chẳng hạn như "loại" của bạn. Nhưng nhận được nhiều hơn "một" kết quả tất nhiên sẽ có liên quan nhiều hơn một chút. Có một số vấn đề JIRA về vấn đề này về việc sửa đổi các toán tử khác để đối phó với n kết quả hoặc "hạn chế" hoặc "lát cắt". Đáng chú ý là SERVER-6074 . Nhưng vấn đề có thể được xử lý theo một số cách.

Các cách triển khai phổ biến của mẫu Active Record rails cho bộ nhớ MongoDB là Mongoid Mongo Mapper , cả hai đều cho phép truy cập vào các chức năng thu thập mongodb "gốc" thông qua .collection người truy cập. Về cơ bản, đây là những gì bạn cần để có thể sử dụng các phương thức gốc, chẳng hạn như .aggregate () hỗ trợ nhiều chức năng hơn so với tổng hợp Bản ghi Hoạt động chung.

Đây là cách tiếp cận tổng hợp với mongoid, mặc dù mã chung không thay đổi khi bạn có quyền truy cập vào đối tượng tập hợp gốc:

require "mongoid"
require "pp";

Mongoid.configure.connect_to("test");

class Item
  include Mongoid::Document
  store_in collection: "item"

  field :type, type: String
  field :pos, type: String
end

Item.collection.drop

Item.collection.insert( :type => "A", :pos => "First" )
Item.collection.insert( :type => "A", :pos => "Second"  )
Item.collection.insert( :type => "A", :pos => "Third" )
Item.collection.insert( :type => "A", :pos => "Forth" )
Item.collection.insert( :type => "B", :pos => "First" )
Item.collection.insert( :type => "B", :pos => "Second" )
Item.collection.insert( :type => "B", :pos => "Third" )
Item.collection.insert( :type => "B", :pos => "Forth" )

res = Item.collection.aggregate([
  { "$group" => {
      "_id" => "$type",
      "docs" => {
        "$push" => {
          "pos" => "$pos", "type" => "$type"
        }
      },
      "one" => {
        "$first" => {
          "pos" => "$pos", "type" => "$type"
        }
      }
  }},
  { "$unwind" =>  "$docs" },
  { "$project" => {
    "docs" => {
      "pos" => "$docs.pos",
      "type" => "$docs.type",
      "seen" => {
        "$eq" => [ "$one", "$docs" ]
      },
    },
    "one" => 1
  }},
  { "$match" => {
    "docs.seen" => false
  }},
  { "$group" => {
    "_id" => "$_id",
    "one" => { "$first" => "$one" },
    "two" => {
      "$first" => {
        "pos" => "$docs.pos",
        "type" => "$docs.type"
      }
    },
    "splitter" => {
      "$first" => {
        "$literal" => ["one","two"]
      }
    }
  }},
  { "$unwind" => "$splitter" },
  { "$project" => {
    "_id" => 0,
    "type" => {
      "$cond" => [
        { "$eq" => [ "$splitter", "one" ] },
        "$one.type",
        "$two.type"
      ]
    },
    "pos" => {
      "$cond" => [
        { "$eq" => [ "$splitter", "one" ] },
        "$one.pos",
        "$two.pos"
      ]
    }
  }}
])

pp res

Tên trong tài liệu thực sự không được sử dụng bởi mã và tiêu đề trong dữ liệu được hiển thị cho "Đầu tiên", "Thứ hai", v.v., thực sự chỉ ở đó để minh họa rằng bạn thực sự đang nhận được tài liệu "top 2" từ danh sách như một kết quả.

Vì vậy, cách tiếp cận ở đây về cơ bản là tạo một "ngăn xếp" các tài liệu được "nhóm" theo khóa của bạn, chẳng hạn như "loại". Điều đầu tiên ở đây là lấy tài liệu "đầu tiên" từ ngăn xếp đó bằng cách sử dụng $first nhà điều hành.

Các bước tiếp theo khớp với các phần tử "đã thấy" từ ngăn xếp và lọc chúng, sau đó bạn lấy lại tài liệu "tiếp theo" khỏi ngăn xếp bằng cách sử dụng $first nhà điều hành. Các bước cuối cùng trong đó thực sự chỉ để trả tài liệu về dạng ban đầu như được tìm thấy trong đầu vào, đây thường là những gì được mong đợi từ một truy vấn như vậy.

Vì vậy, kết quả tất nhiên chỉ là 2 tài liệu hàng đầu cho mỗi loại:

{ "type"=>"A", "pos"=>"First" }
{ "type"=>"A", "pos"=>"Second" }
{ "type"=>"B", "pos"=>"First" }
{ "type"=>"B", "pos"=>"Second" }

Đã có một cuộc thảo luận dài hơn và phiên bản của vấn đề này cũng như các giải pháp khác trong câu trả lời gần đây:

Tổng hợp Mongodb $ group, hạn chế độ dài của mảng

Về cơ bản, cùng một thứ mặc dù tiêu đề và trường hợp đó đang tìm cách khớp với tối đa 10 mục hàng đầu hoặc lớn hơn. Ở đó cũng có một số mã tạo đường dẫn để xử lý các kết quả phù hợp lớn hơn cũng như một số phương pháp thay thế có thể được xem xét tùy thuộc vào dữ liệu của bạn.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. MongoDB hoạt động chậm khi tải

  2. Nhóm Mongodb và các nhà điều hành dự án

  3. bản đồ / thu nhỏ có thích hợp để tìm giá trị trung bình và chế độ của một bộ giá trị cho nhiều bản ghi không?

  4. Nơi lưu trữ MongoClient ở Django

  5. k8s / python:Làm cách nào để đọc bí mật bằng ứng dụng Kubernetes Python?