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.