MongoDB
 sql >> Teknologi Basis Data >  >> NoSQL >> MongoDB

Kondisi batas berganda di mongodb

Secara umum apa yang Anda gambarkan adalah pertanyaan yang relatif umum di sekitar komunitas MongoDB yang dapat kami gambarkan sebagai "n teratas hasil masalah". Ini adalah ketika diberikan beberapa input yang kemungkinan diurutkan dalam beberapa cara, cara mendapatkan n teratas hasil tanpa bergantung pada nilai indeks arbitrer dalam data.

MongoDB memiliki $first operator yang tersedia untuk kerangka kerja agregasi yang berhubungan dengan bagian "1 teratas" dari masalah, karena ini sebenarnya mengambil item "pertama" yang ditemukan pada batas pengelompokan, seperti "tipe" Anda. Tetapi mendapatkan lebih dari "satu" hasil tentu saja melibatkan sedikit lebih banyak. Ada beberapa masalah JIRA tentang memodifikasi operator lain untuk menangani n hasil atau "membatasi" atau "mengiris". Terutama SERVER-6074 . Tapi masalahnya bisa ditangani dengan beberapa cara.

Implementasi populer dari pola Rails Active Record untuk penyimpanan MongoDB adalah Mongoid dan Mongo Mapper , keduanya mengizinkan akses ke fungsi koleksi mongodb "asli" melalui .collection pengakses. Inilah yang pada dasarnya Anda perlukan untuk dapat menggunakan metode asli seperti .agregat() yang mendukung lebih banyak fungsi daripada agregasi Rekaman Aktif umum.

Berikut adalah pendekatan agregasi dengan mongoid, meskipun kode umum tidak berubah setelah Anda memiliki akses ke objek koleksi asli:

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

Penamaan dalam dokumen sebenarnya tidak digunakan oleh kode, dan judul dalam data yang ditampilkan untuk "Pertama", "Kedua", dll, benar-benar hanya untuk menggambarkan bahwa Anda memang mendapatkan dokumen "2 teratas" dari daftar sebagai hasilnya.

Jadi pendekatan di sini pada dasarnya adalah untuk membuat "tumpukan" dokumen yang "dikelompokkan" berdasarkan kunci Anda, seperti "ketik". Hal pertama di sini adalah mengambil dokumen "pertama" dari tumpukan itu menggunakan $first operator.

Langkah selanjutnya mencocokkan elemen "terlihat" dari tumpukan dan memfilternya, lalu Anda mengambil dokumen "berikutnya" dari tumpukan lagi menggunakan $first operator. Langkah terakhir di sana benar-benar justx untuk mengembalikan dokumen ke bentuk aslinya seperti yang ditemukan di input, yang biasanya diharapkan dari kueri semacam itu.

Jadi hasilnya tentu saja, hanya 2 dokumen teratas untuk setiap jenis:

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

Ada diskusi dan versi yang lebih panjang dari ini serta solusi lain dalam jawaban terbaru ini:

Agregasi Mongodb $group, batasi panjang larik

Pada dasarnya hal yang sama terlepas dari judulnya dan kasing itu ingin mencocokkan hingga 10 entri teratas atau lebih besar. Ada beberapa kode pembuatan saluran di sana juga untuk menangani kecocokan yang lebih besar serta beberapa pendekatan alternatif yang dapat dipertimbangkan bergantung pada data Anda.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. RDD dari BSONObject ke DataFrame

  2. MongoDB:Cara melakukan pencarian teks dan mengurutkan berdasarkan tanggal

  3. Penomoran sisi server dengan bidang larik string dokumen tunggal

  4. Kesalahan pembaruan dokumen luwak

  5. kueri mongo - apakah ada properti?