आम तौर पर आप जो वर्णन कर रहे हैं वह मोंगोडीबी समुदाय के आसपास एक अपेक्षाकृत सामान्य प्रश्न है जिसे हम "शीर्ष n
के रूप में वर्णित कर सकते हैं। परिणाम समस्या"। यह तब होता है जब कुछ इनपुट दिया जाता है जिसे किसी तरह से सॉर्ट किया जाता है, शीर्ष n
कैसे प्राप्त करें डेटा में मनमाने इंडेक्स मानों पर भरोसा किए बिना परिणाम।
MongoDB के पास $first
है
ऑपरेटर जो एकत्रीकरण ढांचे
के लिए उपलब्ध है जो समस्या के "शीर्ष 1" भाग से संबंधित है, क्योंकि यह वास्तव में समूह सीमा पर पाया गया "पहला" आइटम लेता है, जैसे आपका "प्रकार"। लेकिन निश्चित रूप से "एक" से अधिक परिणाम प्राप्त करना थोड़ा अधिक शामिल हो जाता है। n
. से निपटने के लिए अन्य ऑपरेटरों को संशोधित करने के बारे में इस पर कुछ JIRA मुद्दे हैं परिणाम या "प्रतिबंधित" या "टुकड़ा"। विशेष रूप से SERVER-6074
. लेकिन समस्या को कुछ तरीकों से नियंत्रित किया जा सकता है।
MongoDB संग्रहण के लिए रेल सक्रिय रिकॉर्ड पैटर्न के लोकप्रिय कार्यान्वयन हैं Mongoid
और मोंगो मैपर
, दोनों एक .collection
के माध्यम से "मूल" mongodb संग्रह कार्यों तक पहुंच की अनुमति देते हैं एक्सेसर। मूल रूप से आपको मूल विधियों जैसे .एग्रीगेट ()
जो सामान्य सक्रिय रिकॉर्ड एकत्रीकरण की तुलना में अधिक कार्यक्षमता का समर्थन करता है।
यहाँ मोंगोइड के साथ एक एकत्रीकरण दृष्टिकोण है, हालाँकि एक बार जब आप मूल संग्रह वस्तु तक पहुँच प्राप्त कर लेते हैं तो सामान्य कोड नहीं बदलता है:
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
दस्तावेजों में नामकरण वास्तव में कोड द्वारा उपयोग नहीं किया जाता है, और "प्रथम", "द्वितीय" आदि के लिए दिखाए गए डेटा में शीर्षक वास्तव में केवल यह दर्शाने के लिए हैं कि आप वास्तव में सूची से "शीर्ष 2" दस्तावेज़ प्राप्त कर रहे हैं एक परिणाम।
तो यहां दृष्टिकोण अनिवार्य रूप से आपकी कुंजी द्वारा "समूहीकृत" दस्तावेज़ों का "स्टैक" बनाने के लिए है, जैसे "टाइप"। यहां सबसे पहली बात यह है कि $first
ऑपरेटर।
बाद के चरण स्टैक से "देखे गए" तत्वों से मेल खाते हैं और उन्हें फ़िल्टर करते हैं, फिर आप $first
ऑपरेटर। इनपुट में पाए जाने वाले दस्तावेजों को मूल रूप में वापस करने के लिए अंतिम चरण वास्तव में जस्ट एक्स हैं, जो आम तौर पर ऐसी क्वेरी से अपेक्षित होता है।
तो परिणाम निश्चित रूप से है, प्रत्येक प्रकार के लिए केवल शीर्ष 2 दस्तावेज़:
{ "type"=>"A", "pos"=>"First" }
{ "type"=>"A", "pos"=>"Second" }
{ "type"=>"B", "pos"=>"First" }
{ "type"=>"B", "pos"=>"Second" }
इस हालिया उत्तर में इसके साथ-साथ अन्य समाधानों की लंबी चर्चा और संस्करण भी था:
मोंगोडब एग्रीगेशन $group, एरे की लंबाई सीमित करें
शीर्षक के बावजूद अनिवार्य रूप से वही बात और वह मामला 10 शीर्ष प्रविष्टियों या उससे अधिक से मेल खाना चाहता था। बड़े मैचों के साथ-साथ कुछ वैकल्पिक तरीकों से निपटने के लिए वहां कुछ पाइपलाइन जनरेशन कोड भी हैं, जिन पर आपके डेटा के आधार पर विचार किया जा सकता है।