आप यहां जो खो रहे हैं वह यह है कि $lookup
as
. द्वारा निर्दिष्ट आउटपुट फ़ील्ड में एक "सरणी" उत्पन्न करता है इसके तर्कों में। यह MongoDB "रिलेशन्स" की सामान्य अवधारणा है, जिसमें दस्तावेज़ों के बीच "संबंध" को "उप-संपत्ति" के रूप में दर्शाया जाता है जो कि दस्तावेज़ के भीतर ही "अंदर" होता है, या तो एकवचन या कई लोगों के लिए "सरणी" होता है।पी>
चूंकि MongoDB "स्कीमालेस" है, $lookup
. की सामान्य धारणा यह है कि आपका मतलब "कई" है और परिणाम इसलिए "हमेशा" एक सरणी है। तो "एसक्यूएल के समान परिणाम" की तलाश में आपको $unwind
. की आवश्यकता है $lookup
. के बाद वह सरणी . चाहे वह "एक" हो या "अनेक" कोई परिणाम नहीं है, क्योंकि यह अभी भी "हमेशा" एक सरणी है:
db.getCollection.('tb1').aggregate([
// Filter conditions from the source collection
{ "$match": { "status": { "$ne": "closed" } }},
// Do the first join
{ "$lookup": {
"from": "tb2",
"localField": "id",
"foreignField": "profileId",
"as": "tb2"
}},
// $unwind the array to denormalize
{ "$unwind": "$tb2" },
// Then match on the condtion for tb2
{ "$match": { "tb2.profile_type": "agent" } },
// join the second additional collection
{ "$lookup": {
"from": "tb3",
"localField": "tb2.id",
"foreignField": "id",
"as": "tb3"
}},
// $unwind again to de-normalize
{ "$unwind": "$tb3" },
// Now filter the condition on tb3
{ "$match": { "tb3.status": 0 } },
// Project only wanted fields. In this case, exclude "tb2"
{ "$project": { "tb2": 0 } }
])
यहां आपको उन अन्य बातों पर ध्यान देने की आवश्यकता है जो आप अनुवाद में नहीं कर रहे हैं:
अनुक्रम "महत्वपूर्ण" है
एकत्रीकरण पाइपलाइन SQL की तुलना में अधिक "संक्षिप्त रूप से अभिव्यंजक" हैं। उन्हें वास्तव में "चरणों का एक क्रम" . के रूप में सबसे अच्छा माना जाता है डेटा को समेटने और बदलने के लिए डेटा स्रोत पर लागू किया गया। इसका सबसे अच्छा एनालॉग "पाइप" कमांड लाइन निर्देश है, जैसे:
ps -ef | grep mongod | grep -v grep | awk '{ print $1 }'
जहां "पाइप" |
MongoDB एकत्रीकरण "पाइपलाइन" में "पाइपलाइन चरण" के रूप में माना जा सकता है।
जैसे हम $match
. करना चाहते हैं हमारे पहले ऑपरेशन के रूप में "स्रोत" संग्रह से चीजों को फ़िल्टर करने के लिए। और यह आम तौर पर अच्छा अभ्यास है क्योंकि यह किसी भी दस्तावेज़ को हटा देता है जो आगे की शर्तों से आवश्यक शर्तों को पूरा नहीं करता है। ठीक वैसे ही जैसे हमारे "कमांड लाइन पाइप" उदाहरण में हो रहा है, जहां हम "इनपुट" और फिर "पाइप" को एक grep
में लेते हैं। "निकालें" या "फ़िल्टर" करने के लिए।
पथ महत्वपूर्ण हैं
जहां अगला काम आप यहां करते हैं $lookup
. के माध्यम से "शामिल हों" . परिणाम "from"
. से आइटम की "सरणी" है "as"
. में आउटपुट के लिए आपूर्ति किए गए फ़ील्ड द्वारा मिलान किए गए संग्रह तर्क "फ़ील्ड पथ" एक "सरणी" के रूप में।
यहां चुना गया नामकरण महत्वपूर्ण है, क्योंकि अब स्रोत संग्रह से "दस्तावेज़" उस दिए गए पथ पर "जॉइन" से अब तक मौजूद सभी वस्तुओं पर विचार करता है। इसे आसान बनाने के लिए, मैं नए "पथ" के लिए "जॉइन" के समान "संग्रह" नाम का उपयोग करता हूं।
तो पहले "जुड़ने" से शुरू होने वाला आउटपुट "tb2"
. है और वह उस संग्रह के सभी परिणामों को धारण करेगा। $unwind
. के निम्नलिखित क्रम के साथ एक महत्वपूर्ण बात भी ध्यान देने योग्य है और फिर $match
, कि कैसे MongoDB वास्तव में क्वेरी को संसाधित करता है।
कुछ अनुक्रम "वास्तव में" मायने रखते हैं
चूंकि यह "दिखता है" वहाँ "तीन" पाइपलाइन चरण हैं, $lookup
. होने के नाते फिर $unwind
और फिर $match
. लेकिन "तथ्य" में MongoDB वास्तव में कुछ और करता है, जो कि { "explain": true }
के आउटपुट में प्रदर्शित होता है। .aggregate()
. में जोड़ा गया आदेश:
{
"$lookup" : {
"from" : "tb2",
"as" : "tb2",
"localField" : "id",
"foreignField" : "profileId",
"unwinding" : {
"preserveNullAndEmptyArrays" : false
},
"matching" : {
"profile_type" : {
"$eq" : "agent"
}
}
}
},
{
"$lookup" : {
"from" : "tb3",
"as" : "tb3",
"localField" : "tb2.id",
"foreignField" : "id",
"unwinding" : {
"preserveNullAndEmptyArrays" : false
},
"matching" : {
"status" : {
"$eq" : 0.0
}
}
}
},
तो "अनुक्रम" के पहले बिंदु से अलग जहां आपको $match
. लगाने की आवश्यकता है बयान जहां उनकी आवश्यकता होती है और "सबसे अच्छा" करते हैं, यह वास्तव में "जुड़ने" की अवधारणा के साथ "वास्तव में महत्वपूर्ण" हो जाता है। यहां ध्यान देने वाली बात यह है कि $lookup
. के हमारे क्रम फिर $unwind
और फिर $match
, वास्तव में MongoDB द्वारा केवल $lookup
. के रूप में संसाधित किया जाता है चरणों, अन्य कार्यों के साथ प्रत्येक के लिए एक पाइपलाइन चरण में "लुढ़का"।
$lookup
. द्वारा प्राप्त परिणामों को "फ़िल्टरिंग" करने के अन्य तरीकों के लिए यह एक महत्वपूर्ण अंतर है . चूंकि इस मामले में, $match
. से "शामिल होने" पर वास्तविक "क्वेरी" शर्तें "पहले" में शामिल होने के लिए संग्रह पर प्रदर्शन किया जाता है, परिणाम माता-पिता को वापस कर दिए जाते हैं।
यह $unwind
. के संयोजन में है (जिसका अनुवाद unwinding
. में किया गया है ) जैसा कि ऊपर दिखाया गया है कि MongoDB वास्तव में इस संभावना से कैसे निपटता है कि "जॉइन" के परिणामस्वरूप स्रोत दस्तावेज़ में सामग्री की एक सरणी का उत्पादन हो सकता है जिसके कारण यह 16MB BSON सीमा से अधिक हो जाता है। यह केवल उन मामलों में होगा जहां परिणाम में शामिल होने का परिणाम बहुत बड़ा होता है, लेकिन वही लाभ होता है जहां "फ़िल्टर" वास्तव में लागू होता है, लक्ष्य संग्रह पर होने से "पहले" परिणाम वापस आ जाते हैं।
यह उस तरह की हैंडलिंग है जो SQL जॉइन के समान व्यवहार के लिए सबसे अच्छा "सहसंबद्ध" है। इसलिए यह $lookup
. से परिणाम प्राप्त करने का सबसे प्रभावी तरीका भी है जहां "विदेशी" प्रमुख मूल्यों के "स्थानीय" के अलावा जॉइन पर लागू होने के लिए अन्य शर्तें हैं।
यह भी ध्यान दें कि अन्य व्यवहार परिवर्तन वह है जो अनिवार्य रूप से $lookup
द्वारा किया गया एक LEFT JOIN है जहां "लक्ष्य" संग्रह में मेल खाने वाले दस्तावेज़ की उपस्थिति की परवाह किए बिना "स्रोत" दस्तावेज़ हमेशा बनाए रखा जाएगा। इसके बजाय $unwind
$match
में अतिरिक्त शर्तों द्वारा "स्रोत" से किसी भी परिणाम को "त्याग" करके इसमें जोड़ा जाता है जिसमें "लक्ष्य" से मेल खाने वाला कुछ भी नहीं होता है ।
वास्तव में निहित preserveNullAndEmptyArrays: false
के कारण उन्हें पहले ही खारिज कर दिया जाता है। जो शामिल है और कुछ भी छोड़ देगा जहां "स्थानीय" और "विदेशी" कुंजी दो संग्रहों के बीच मेल नहीं खातीं। इस विशेष प्रकार की क्वेरी के लिए यह एक अच्छी बात है क्योंकि "जॉइन" का उद्देश्य उन मानों पर "बराबर" करना है।
समाप्त करें
जैसा कि पहले उल्लेख किया गया है, मोंगोडीबी आम तौर पर "रिलेशनल डेटाबेस" या आरडीबीएमएस का उपयोग करने के तरीके के लिए "संबंधों" को बहुत अलग तरीके से मानता है। "रिश्तों" की सामान्य अवधारणा वास्तव में डेटा को "एम्बेडिंग" करती है, या तो एक संपत्ति के रूप में या एक सरणी के रूप में।
आप वास्तव में ऐसे आउटपुट की इच्छा कर सकते हैं, जो कि $unwind
. के बिना भी इसका एक कारण है यहां $lookup
. का आउटपुट अनुक्रमित करें वास्तव में एक "सरणी" है। हालांकि $unwind
. का उपयोग कर रहे हैं इस संदर्भ में वास्तव में सबसे प्रभावी काम है, साथ ही यह गारंटी देना कि "शामिल" डेटा वास्तव में उपरोक्त बीएसओएन सीमा को उस "शामिल" के परिणामस्वरूप पार नहीं करता है।
यदि आप वास्तव में आउटपुट की सरणियाँ चाहते हैं, तो यहाँ करने के लिए सबसे अच्छी बात यह होगी कि $group
का उपयोग किया जाए पाइपलाइन चरण, और संभवतः $unwind
के "सामान्यीकृत" और "परिणाम पूर्ववत" करने के लिए कई चरणों के रूप में
{ "$group": {
"_id": "$_id",
"tb1_field": { "$first": "$tb1_field" },
"tb1_another": { "$first": "$tb1_another" },
"tb3": { "$push": "$tb3" }
}}
जहां आप वास्तव में इस मामले के लिए "tb1"
. से आवश्यक सभी फ़ील्ड सूचीबद्ध करेंगे $first
. का उपयोग करके उनकी संपत्ति के नाम से केवल "पहली" घटना को बनाए रखने के लिए (अनिवार्य रूप से "tb2"
. के परिणामों द्वारा दोहराया गया और "tb3"
unwound ) और फिर $push
"tb3"
. से "विवरण" "tb1"
. के संबंध को दर्शाने के लिए एक "सरणी" में ।
लेकिन दिए गए एकत्रीकरण पाइपलाइन का सामान्य रूप इस बात का सटीक प्रतिनिधित्व है कि मूल एसक्यूएल से परिणाम कैसे प्राप्त होंगे, जो "जॉइन" के परिणामस्वरूप "डिनॉर्मलाइज्ड" आउटपुट है। इसके बाद आप परिणामों को फिर से "सामान्यीकृत" करना चाहते हैं या नहीं।