सीधे अपने प्रश्न का उत्तर देने के लिए, हाँ यह सबसे कारगर तरीका है। लेकिन मुझे लगता है कि हमें यह स्पष्ट करने की आवश्यकता है कि ऐसा क्यों है।
जैसा कि विकल्पों में सुझाया गया था, एक चीज जो लोग देख रहे हैं, वह है $group
पर जाने से पहले आपके परिणामों को "क्रमबद्ध करना" स्टेज और वे जो देख रहे हैं वह "टाइमस्टैम्प" मान है, इसलिए आप यह सुनिश्चित करना चाहेंगे कि सब कुछ "टाइमस्टैम्प" क्रम में है, इसलिए फ़ॉर्म:
db.temperature.aggregate([
{ "$sort": { "station": 1, "dt": -1 } },
{ "$group": {
"_id": "$station",
"result": { "$first":"$dt"}, "t": {"$first":"$t"}
}}
])
और जैसा कि कहा गया है कि आप निश्चित रूप से एक इंडेक्स को प्रतिबिंबित करना चाहेंगे ताकि सॉर्ट को कुशल बनाया जा सके:
हालाँकि, और यह वास्तविक बिंदु है। ऐसा लगता है कि दूसरों ने (यदि आपके लिए ऐसा नहीं है तो) अनदेखा कर दिया है कि यह सारा डेटा संभवतः पहले से ही डाला जा रहा है समय क्रम में, जिसमें प्रत्येक पठन को जोड़े के रूप में दर्ज किया जाता है।
तो इसकी खूबसूरती है _id
फ़ील्ड (डिफ़ॉल्ट ObjectId
. के साथ ) पहले से ही "टाइमस्टैम्प" क्रम में है, क्योंकि इसमें वास्तव में एक समय मान होता है और यह कथन को संभव बनाता है:
db.temperature.aggregate([
{ "$group": {
"_id": "$station",
"result": { "$last":"$dt"}, "t": {"$last":"$t"}
}}
])
और यह है और तेज। क्यों? वैसे आपको एक इंडेक्स (आह्वान करने के लिए अतिरिक्त कोड) का चयन करने की आवश्यकता नहीं है, आपको दस्तावेज़ के अलावा इंडेक्स को "लोड" करने की भी आवश्यकता नहीं है।
हम पहले से ही जानते हैं कि दस्तावेज़ क्रम में हैं ( _id
. द्वारा ) तो $last
सीमाएँ पूरी तरह से मान्य हैं। आप वैसे भी सब कुछ स्कैन कर रहे हैं, और आप _id
. पर क्वेरी को "रेंज" भी कर सकते हैं दो तिथियों के बीच समान रूप से मान्य मान।
यहां केवल वास्तविक बात यह है कि "असली दुनिया" के उपयोग में, आपके लिए $match
अधिक व्यावहारिक हो सकता है "पहला" और "आखिरी" _id
प्राप्त करने के विरोध में इस प्रकार का संचय करते समय तिथियों की श्रेणियों के बीच मान एक "श्रेणी" या आपके वास्तविक उपयोग में समान कुछ परिभाषित करने के लिए।
तो इसका प्रमाण कहाँ है? वैसे इसे पुन:पेश करना काफी आसान है, इसलिए मैंने कुछ नमूना डेटा उत्पन्न करके ऐसा किया:
var stations = [
"AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL",
"GA", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA",
"ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE",
"NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK",
"OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT",
"VA", "WA", "WV", "WI", "WY"
];
for ( i=0; i<200000; i++ ) {
var station = stations[Math.floor(Math.random()*stations.length)];
var t = Math.floor(Math.random() * ( 96 - 50 + 1 )) +50;
dt = new Date();
db.temperatures.insert({
station: station,
t: t,
dt: dt
});
}
मेरे हार्डवेयर पर (स्पिनी डिस्क के साथ 8GB लैपटॉप, जो तारकीय नहीं है, लेकिन निश्चित रूप से पर्याप्त है) स्टेटमेंट के प्रत्येक रूप को चलाने से स्पष्ट रूप से एक इंडेक्स और एक सॉर्ट (सॉर्ट स्टेटमेंट के रूप में इंडेक्स पर समान कुंजी) का उपयोग करके संस्करण के साथ एक उल्लेखनीय विराम दिखाई देता है। यह केवल एक छोटा विराम है, लेकिन अंतर काफी महत्वपूर्ण है।
यहां तक कि व्याख्या आउटपुट (संस्करण 2.6 और ऊपर, या वास्तव में 2.4.9 में है, हालांकि दस्तावेज नहीं है) को देखकर आप उसमें अंतर देख सकते हैं, हालांकि $sort
एक सूचकांक की उपस्थिति के कारण अनुकूलित किया गया है, लिया गया समय सूचकांक चयन और फिर अनुक्रमित प्रविष्टियों को लोड करने के साथ प्रतीत होता है। "कवर" . के लिए सभी फ़ील्ड सहित अनुक्रमणिका क्वेरी से कोई फ़र्क नहीं पड़ता।
इसके अलावा रिकॉर्ड के लिए, तारीख को पूरी तरह से अनुक्रमणित करना और केवल दिनांक मानों को क्रमबद्ध करना एक ही परिणाम देता है। संभवत:थोड़ा तेज, लेकिन फिर भी बिना क्रम के प्राकृतिक सूचकांक रूप की तुलना में धीमा।
तो जब तक आप खुशी से पहले . पर "रेंज" कर सकते हैं और अंतिम _id
मान, तो यह सच है कि सम्मिलन आदेश पर प्राकृतिक अनुक्रमणिका का उपयोग करना वास्तव में ऐसा करने का सबसे प्रभावी तरीका है। आपका वास्तविक विश्व लाभ इस बात पर भिन्न हो सकता है कि यह आपके लिए व्यावहारिक है या नहीं और यह सूचकांक को लागू करने और तिथि को क्रमबद्ध करने के लिए अधिक सुविधाजनक हो सकता है।
लेकिन अगर आप _id
. का उपयोग करके खुश थे श्रेणी या "अंतिम" _id
. से अधिक हो अपनी क्वेरी में, तो शायद अपने परिणामों के साथ मान प्राप्त करने के लिए एक ट्वीक करें ताकि आप वास्तव में उस जानकारी को लगातार प्रश्नों में संग्रहीत और उपयोग कर सकें:
db.temperature.aggregate([
// Get documents "greater than" the "highest" _id value found last time
{ "$match": {
"_id": { "$gt": ObjectId("536076603e70a99790b7845d") }
}},
// Do the grouping with addition of the returned field
{ "$group": {
"_id": "$station",
"result": { "$last":"$dt"},
"t": {"$last":"$t"},
"lastDoc": { "$last": "$_id" }
}}
])
और यदि आप वास्तव में उस तरह के परिणामों का "अनुसरण कर रहे थे" तो आप ObjectId
का अधिकतम मान निर्धारित कर सकते हैं अपने परिणामों से और अगली क्वेरी में इसका इस्तेमाल करें।
किसी भी तरह, उसके साथ खेलने का मज़ा लें, लेकिन फिर से हाँ, इस मामले में वह क्वेरी सबसे तेज़ तरीका है।