क्वेरी उतनी जटिल नहीं है जितनी पहली नज़र में लग सकती है - आपके द्वारा दी गई सीमा को "ओवरलैप" करने वाले सभी दस्तावेज़ों को खोजने के लिए क्वेरी है:
db.test.find( { "startTime" : { "$lt" : new_end_time },
"endTime" : { "$gt": new_start_time }
}
)
यह हमारी समाप्ति तिथि से पहले की आरंभ तिथि और हमारे प्रारंभ समय से अधिक समाप्ति तिथि वाले किसी भी दस्तावेज़ से मेल खाएगा। यदि आप श्रेणियों को एक रेखा पर बिंदुओं के रूप में देखते हैं:
-----|*********|----------|****|-----------|******||********|--- s1 e1 s2 e2 s3 e3s4 e4
sX-eX जोड़े मौजूदा श्रेणियों का प्रतिनिधित्व करते हैं। यदि आप एक नया s5-e5 लेते हैं तो आप देख सकते हैं कि यदि हम बाद शुरू होने वाले जोड़ों को हटा दें हमारी समाप्ति तिथि (वे हमें ओवरलैप नहीं कर सकते हैं) और फिर हम उन सभी जोड़ियों को समाप्त कर देते हैं जो हमारी प्रारंभ तिथि से पहले समाप्त हो जाती हैं, यदि हमारे पास कुछ भी नहीं बचा है, तो हम डालने के लिए अच्छे हैं।
वह शर्त यह होगी कि समाप्ति तिथि $lte
. के साथ सभी दस्तावेज़ों का एक संघ हो हमारे प्रारंभ और प्रारंभ दिनांक वाले $gte
हमारे संग्रह में पहले से मौजूद सभी दस्तावेज़ शामिल हैं। हमारी क्वेरी यह सुनिश्चित करने के लिए चारों ओर फ़्लिप करती है कि कोई भी दस्तावेज़ इस शर्त के विपरीत को संतुष्ट नहीं करता है।
प्रदर्शन के मोर्चे पर, यह दुर्भाग्यपूर्ण है कि आप अपनी तिथियों को केवल तार के रूप में संग्रहीत कर रहे हैं। यदि आपने उन्हें टाइमस्टैम्प (या किसी भी संख्या, वास्तव में) के रूप में संग्रहीत किया है, तो आप इस क्वेरी को इंडेक्स का बेहतर उपयोग कर सकते हैं। वैसे भी, प्रदर्शन के लिए आप { "startTime":1, "endTime":1 }
पर एक इंडेक्स रखना चाहेंगे। ।
यह पता लगाना आसान है कि आप जिस श्रेणी को सम्मिलित करना चाहते हैं वह किसी मौजूदा श्रेणी को ओवरलैप करती है या नहीं, लेकिन आपके दूसरे प्रश्न पर:
एक आवेषण के साथ ऐसा करने का कोई उचित तरीका नहीं है क्योंकि वे कोई प्रश्न नहीं लेते हैं (यानी वे सशर्त नहीं हैं)।
हालाँकि, आप अप्सर्ट कंडीशन वाले अपडेट का उपयोग कर सकते हैं। यदि शर्त किसी चीज़ से मेल नहीं खाती है तो यह सम्मिलित कर सकता है, लेकिन यदि यह मेल खाता है, तो यह मिलान किए गए दस्तावेज़ को अपडेट करने का प्रयास करेगा!
तो आप जिस ट्रिक का उपयोग करेंगे वह अपडेट को एक नोप बना देगा, और उन फ़ील्ड्स को सेट करें जिनकी आपको आवश्यकता है केवल अप्सर्ट पर। 2.4 के बाद से एक $setOnInsert
. है अद्यतन करने के लिए ऑपरेटर। पूरी चीज़ कुछ इस तरह दिखेगी:
db.test.update(
{ startTime: { "$lt" : new_end_time }, "endTime" : { "$gt": new_start_time } },
{ $setOnInsert:{ startTime:new_start_time, endTime: new_end_time}},
{upsert:1}
)
WriteResult({
"nMatched" : 0,
"nUpserted" : 1,
"nModified" : 0,
"_id" : ObjectId("538e0f6e7110dddea4383938")
})
db.test.update(
{ startTime:{ "$lt" : new_end_time }, "endTime" : { "$gt": new_start_time } },
{ $setOnInsert:{ startTime:new_start_time, endTime: new_end_time}},
{upsert:1}
)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
मैंने वही "अपडेट" दो बार किया - पहली बार, कोई ओवरलैप दस्तावेज़ नहीं था, इसलिए अपडेट ने एक "अप्सर्ट" किया जिसे आप WriteResult
में देख सकते हैं। यह वापस आ गया।
जब मैंने इसे दूसरी बार चलाया, तो यह ओवरलैप हो जाएगा (बेशक, निश्चित रूप से) इसलिए इसने मिलान किए गए दस्तावेज़ को अपडेट करने का प्रयास किया, लेकिन देखा कि ऐसा करने के लिए कोई काम नहीं था। आप देख सकते हैं कि लौटा हुआ nMatched 1 है लेकिन कुछ भी डाला या संशोधित नहीं किया गया था।