MongoDB में $ खोल ऑपरेटर क्या है?


103

यह MongoDB के साथ मेरा पहला दिन है इसलिए कृपया मेरे साथ आसान करें :)

मैं समझ नहीं पा रहा हूं $unwind ऑपरेटर सकता, शायद इसलिए कि अंग्रेजी मेरी मूल भाषा नहीं है।

db.article.aggregate(
    { $project : {
        author : 1 ,
        title : 1 ,
        tags : 1
    }},
    { $unwind : "$tags" }
);

प्रोजेक्ट ऑपरेटर कुछ ऐसा है जिसे मैं समझ सकता हूं, मुझे लगता है (यह पसंद है SELECT, है न?)। परन्तु फिर,$unwind (हवाला देते हुए) हर स्रोत दस्तावेज़ के भीतर अनलॉन्ड सरणी के प्रत्येक सदस्य के लिए एक दस्तावेज़ देता है

यह एक तरह है JOIN? यदि हां, तो कैसे का परिणाम $project(के साथ _id, author,title और tagsक्षेत्रों) के साथ तुलना की जा सकती tagsसरणी?

नोट : मैंने MongoDB वेबसाइट से उदाहरण लिया है, मुझे tagsसरणी की संरचना नहीं पता है । मुझे लगता है कि यह टैग नामों का एक सरल सरणी है।

जवाबों:


235

सबसे पहले, MongoDB में आपका स्वागत है!

याद रखने वाली बात यह है कि MongoDB डेटा स्टोरेज के लिए "NoSQL" अप्रोच को नियोजित करता है, इसलिए अपने दिमाग में सेलेक्ट्स, जॉइन आदि के विचारों को नष्ट कर दें। आपके डेटा को संग्रहीत करने का तरीका दस्तावेज़ों और संग्रहों के रूप में है, जो आपके संग्रहण स्थानों से डेटा जोड़ने और प्राप्त करने के एक गतिशील साधन की अनुमति देता है।

कहा जा रहा है, $ खोल पैरामीटर के पीछे की अवधारणा को समझने के लिए, आपको पहले यह समझना चाहिए कि आप जिस मामले का उपयोग करने की कोशिश कर रहे हैं वह क्या कह रहा है। Mongodb.org से उदाहरण दस्तावेज इस प्रकार है:

{
 title : "this is my title" ,
 author : "bob" ,
 posted : new Date () ,
 pageViews : 5 ,
 tags : [ "fun" , "good" , "fun" ] ,
 comments : [
             { author :"joe" , text : "this is cool" } ,
             { author :"sam" , text : "this is bad" }
 ],
 other : { foo : 5 }
}

ध्यान दें कि टैग वास्तव में 3 आइटमों की एक सरणी है, इस मामले में "मज़ेदार", "अच्छा" और "मज़ेदार" है।

क्या $ खोलना आपको प्रत्येक तत्व के लिए एक दस्तावेज़ को छीलने की अनुमति देता है और परिणामस्वरूप दस्तावेज़ देता है। शास्त्रीय दृष्टिकोण में इस पर विचार करने के लिए, "टैग सरणी में प्रत्येक आइटम के लिए, केवल उस आइटम के साथ एक दस्तावेज़ लौटाया जाना" होगा।

इस प्रकार, निम्नलिखित को चलाने का परिणाम है:

db.article.aggregate(
    { $project : {
        author : 1 ,
        title : 1 ,
        tags : 1
    }},
    { $unwind : "$tags" }
);

निम्नलिखित दस्तावेज वापस करेंगे:

{
     "result" : [
             {
                     "_id" : ObjectId("4e6e4ef557b77501a49233f6"),
                     "title" : "this is my title",
                     "author" : "bob",
                     "tags" : "fun"
             },
             {
                     "_id" : ObjectId("4e6e4ef557b77501a49233f6"),
                     "title" : "this is my title",
                     "author" : "bob",
                     "tags" : "good"
             },
             {
                     "_id" : ObjectId("4e6e4ef557b77501a49233f6"),
                     "title" : "this is my title",
                     "author" : "bob",
                     "tags" : "fun"
             }
     ],
     "OK" : 1
}

ध्यान दें कि परिणाम सरणी में केवल एक चीज बदल रही है जो टैग मूल्य में वापस आ रही है। यदि आपको यह कैसे काम करता है पर एक अतिरिक्त संदर्भ की आवश्यकता है, तो मैंने यहां एक लिंक शामिल किया है । उम्मीद है कि यह मदद करता है, और सबसे अच्छा NoSQL सिस्टम है कि मैं इस प्रकार अब तक भर में आया है में से एक में अपने भाग्य के साथ शुभकामनाएँ।


44

$unwind सरणी तत्व के अनुसार, एक बार पाइपलाइन में प्रत्येक दस्तावेज़ को डुप्लिकेट करता है।

इसलिए यदि आपके इनपुट पाइपलाइन में दो तत्वों के साथ एक लेख डॉक है tags, {$unwind: '$tags'}तो पाइपलाइन को दो लेख डॉक्स में बदल देगा जो tagsक्षेत्र को छोड़कर समान हैं । पहले डॉक्टर में, tagsमूल डॉक्टर के सरणी से पहला तत्व होगा, और दूसरे डॉक्टर में, tagsदूसरा तत्व होगा।


22

आइए इसे एक उदाहरण से समझते हैं

यह कंपनी का दस्तावेज कैसा दिखता है:

मूल दस्तावेज़

$unwindहमें इनपुट के रूप में दस्तावेज़ लेने की अनुमति देता है, जिसमें एक सरणी मूल्यवान फ़ील्ड होती है और आउटपुट दस्तावेज़ पैदा करता है, जैसे कि सरणी में प्रत्येक तत्व के लिए एक आउटपुट दस्तावेज़ होता है। स्रोत

$ खोलना मंच

तो चलिए अपनी कंपनियों के उदाहरणों पर वापस जाते हैं, और आराम के चरणों के उपयोग पर एक नज़र डालते हैं। यह प्रश्न:


db.companies.aggregate([
    { $match: {"funding_rounds.investments.financial_org.permalink": "greylock" } },
    { $project: {
        _id: 0,
        name: 1,
        amount: "$funding_rounds.raised_amount",
        year: "$funding_rounds.funded_year"
    } }
])

उन दस्तावेज़ों का निर्माण करता है जिनमें राशि और वर्ष दोनों के लिए सरणियाँ होती हैं।

परियोजना का उत्पादन

क्योंकि हम फंडिंग राउंड एरे के भीतर हर तत्व के लिए जुटाई गई राशि और वित्त पोषित वर्ष तक पहुंच रहे हैं। इसे ठीक करने के लिए, हम इस एकत्रीकरण पाइपलाइन में अपनी परियोजना के चरण से पहले एक खोल अवस्था को शामिल कर सकते हैं, और यह कहकर इसे मानकीकृत कर सकते हैं कि हम unwindफंडिंग राउंड ऐरे को चाहते हैं :


db.companies.aggregate([
    { $match: {"funding_rounds.investments.financial_org.permalink": "greylock" } },
    { $unwind: "$funding_rounds" },
    { $project: {
        _id: 0,
        name: 1,
        amount: "$funding_rounds.raised_amount",
        year: "$funding_rounds.funded_year"
    } }
])

खोलना इनपुट के रूप में प्राप्त करता है की तुलना में अगले चरण में और अधिक दस्तावेजों के लिए outputting का प्रभाव है

यदि हम funding_roundsसरणी को देखते हैं, तो हम जानते हैं कि प्रत्येक के लिए funding_rounds, एक raised_amountऔर एक funded_yearक्षेत्र है। तो, unwindहर एक दस्तावेज के लिए, जो कि funding_roundsएरे के तत्व हैं, एक आउटपुट डॉक्यूमेंट तैयार करते हैं। अब, इस उदाहरण में, हमारे मूल्य हैं string। लेकिन, एक सरणी में तत्वों के लिए मूल्य के प्रकार की परवाह किए बिना, unwindइनमें से हर एक मान के लिए एक आउटपुट दस्तावेज़ का उत्पादन करेगा, जैसे कि प्रश्न में फ़ील्ड में केवल वह तत्व होगा। के मामले में funding_rounds, वह तत्व इन दस्तावेजों में से funding_roundsप्रत्येक के लिए मूल्य के रूप में एक दस्तावेज होगा जो हमारे projectमंच पर पारित हो जाता है । इसका परिणाम यह होता है कि अब हमें amountए और ए मिलता है yearप्रत्येक कंपनी के लिए प्रत्येक फंडिंग राउंड के लिए एकहमारे संग्रह में। इसका मतलब यह है कि हमारे मैच ने कई कंपनी दस्तावेजों का उत्पादन किया और उन दस्तावेजों में से हर एक कंपनी के कई दस्तावेजों का परिणाम है। प्रत्येक कंपनी के दस्तावेज़ के भीतर प्रत्येक फंडिंग राउंड के लिए एक। मंच unwindसे इसे सौंपे गए दस्तावेजों का उपयोग करके यह ऑपरेशन करता है match। और फिर हर कंपनी के लिए ये सभी दस्तावेज projectस्टेज पर पहुंच जाते हैं।

उत्पादन कम करना

तो, सभी दस्तावेजों जहां funder था Greylock (क्वेरी उदाहरण के रूप में) दस्तावेजों की एक संख्या में विभाजित किया जाएगा, हर कंपनी फ़िल्टर से मेल खाने के लिए धन राउंड की संख्या के बराबर $match: {"funding_rounds.investments.financial_org.permalink": "greylock" }। और फिर हर एक परिणामी दस्तावेज को हमारे पास भेजा जाएगा project। अब, unwindइनपुट के रूप में प्राप्त होने वाले प्रत्येक दस्तावेज़ के लिए एक सटीक प्रतिलिपि बनाता है। सभी क्षेत्रों में एक ही अपवाद के साथ एक ही कुंजी और मूल्य है, और वह यह है कि दस्तावेज़ों funding_roundsकी एक सरणी होने के बजाय फ़ील्ड funding_roundsमें एक मान है जो एक एकल दस्तावेज़ है, जो कि एक व्यक्तिगत फंडिंग राउंड है। तो, एक कंपनी जिसके पास 4 फंडिंग राउंड हैं, में परिणाम देगाunwind 4 निर्माणदस्तावेजों। जहाँ हर क्षेत्र एक सटीक प्रति है, केवल उस funding_roundsक्षेत्र को छोड़कर , जो उन प्रतियों में से प्रत्येक के लिए एक सरणी होने के बजाय funding_roundsकंपनी के दस्तावेज़ से सरणी से एक व्यक्तिगत तत्व होगा जो unwindवर्तमान में प्रसंस्करण कर रहा है। इसलिए, unwindइनपुट के रूप में इसे प्राप्त करने से अधिक दस्तावेजों के अगले चरण में आउटपुट करने का प्रभाव है। इसका मतलब यह है कि हमारे projectमंच को अब एक funding_roundsफ़ील्ड मिलता है जो फिर से एक सरणी नहीं है, बल्कि एक नेस्टेड दस्तावेज़ है जिसमें ए raised_amountऔर funded_yearफ़ील्ड है। इसलिए, projectप्रत्येक कंपनी matchको फ़िल्टर के लिए कई दस्तावेज़ प्राप्त होंगे और इसलिए प्रत्येक दस्तावेज़ को व्यक्तिगत रूप से संसाधित कर सकते हैं और प्रत्येक कंपनी के लिए प्रत्येक फंडिंग राउंड के लिए एक व्यक्तिगत राशि और वर्ष की पहचान कर सकते हैं।


2
उसी दस्तावेज का उपयोग करना बेहतर होगा।
जेब 50

1
$ खोल के लिए एक पहले उपयोग के मामले के रूप में मैं नेस्टेड सेट के बहुत जटिल नेस्टेड था। मोंगो डॉक्स और स्टैकओवरफ़्लो के बीच जा रहे हैं, आपके जवाब ने आखिरकार मुझे $ प्रोजेक्ट और $ बेहतर तरीके से समझने में मदद की। धन्यवाद @Zameer!
सात

3

आधिकारिक दस्तावेज के अनुसार:

$ प्रत्येक तत्व के लिए एक दस्तावेज़ को आउटपुट करने के लिए इनपुट दस्तावेज़ों से एक सरणी फ़ील्ड को खोल देता है। प्रत्येक आउटपुट दस्तावेज़ तत्व द्वारा प्रतिस्थापित सरणी फ़ील्ड के मान के साथ इनपुट दस्तावेज़ है।

मूल उदाहरण के माध्यम से स्पष्टीकरण:

एक संग्रह सूची में निम्नलिखित दस्तावेज हैं:

{ "_id" : 1, "item" : "ABC", "sizes": [ "S", "M", "L"] }
{ "_id" : 2, "item" : "EFG", "sizes" : [ ] }
{ "_id" : 3, "item" : "IJK", "sizes": "M" }
{ "_id" : 4, "item" : "LMN" }
{ "_id" : 5, "item" : "XYZ", "sizes" : null }

निम्नलिखित $ खोलना परिचालन समतुल्य हैं और आकार क्षेत्र में प्रत्येक तत्व के लिए एक दस्तावेज लौटाते हैं । यदि आकार फ़ील्ड किसी सरणी पर हल नहीं करता है, लेकिन गायब नहीं है, अशक्त है, या खाली सरणी नहीं है, तो $ नॉन-सरणी ऑपरेंड को एकल तत्व सरणी के रूप में अनुभव करता है।

db.inventory.aggregate( [ { $unwind: "$sizes" } ] )

या

db.inventory.aggregate( [ { $unwind: { path: "$sizes" } } ] 

क्वेरी आउटपुट के ऊपर:

{ "_id" : 1, "item" : "ABC", "sizes" : "S" }
{ "_id" : 1, "item" : "ABC", "sizes" : "M" }
{ "_id" : 1, "item" : "ABC", "sizes" : "L" }
{ "_id" : 3, "item" : "IJK", "sizes" : "M" }

इसकी आवश्यकता क्यों है?

एकत्रीकरण करते समय $ खोलना बहुत उपयोगी है। यह विभिन्न दस्तावेजों जैसे कि छँटाई, खोज आदि के प्रदर्शन से पहले सरल दस्तावेज़ में जटिल / नेस्टेड दस्तावेज़ को तोड़ता है।

$ खोलना के बारे में अधिक जानने के लिए:

https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/

एकत्रीकरण के बारे में अधिक जानने के लिए:

https://docs.mongodb.com/manual/reference/operator/aggregation-pipeline/


2

इस डेटा को एक संग्रह में समझने के लिए नीचे दिए गए उदाहरण पर विचार करें

{
        "_id" : 1,
        "shirt" : "Half Sleeve",
        "sizes" : [
                "medium",
                "XL",
                "free"
        ]
}

क्वेरी - db.test1.aggregate ([{$ खोलना: "$ आकार"}]);

उत्पादन

{ "_id" : 1, "shirt" : "Half Sleeve", "sizes" : "medium" }
{ "_id" : 1, "shirt" : "Half Sleeve", "sizes" : "XL" }
{ "_id" : 1, "shirt" : "Half Sleeve", "sizes" : "free" }

1

मुझे RDBMS तरीके से कोरल किए गए तरीके से समझाएं। यह कथन है:

db.article.aggregate(
    { $project : {
        author : 1 ,
        title : 1 ,
        tags : 1
    }},
    { $unwind : "$tags" }
);

दस्तावेज़ / रिकॉर्ड पर लागू करने के लिए :

{
 title : "this is my title" ,
 author : "bob" ,
 posted : new Date () ,
 pageViews : 5 ,
 tags : [ "fun" , "good" , "fun" ] ,
 comments : [
             { author :"joe" , text : "this is cool" } ,
             { author :"sam" , text : "this is bad" }
 ],
 other : { foo : 5 }
}

$ परियोजना / चयन बस के रूप में इन क्षेत्र / स्तंभों रिटर्न

लेखक का चयन करें , शीर्षक, लेख से टैग

अगला, मानगो का मजेदार हिस्सा है, इस सरणी tags : [ "fun" , "good" , "fun" ]को किसी अन्य संबंधित तालिका के रूप में मानें (कोई लुकअप / संदर्भ तालिका नहीं हो सकती क्योंकि मानों में कुछ दोहराव हैं) जिसका नाम "टैग" है। याद रखें सिलेक्ट आम तौर पर खड़ी चीजों का उत्पादन करता है, इसलिए "टैग" को खोलना विभाजन करना है () ऊर्ध्वाधर रूप से तालिका "टैग" में।

$ परियोजना का अंतिम परिणाम + $ खोलना: यहां छवि विवरण दर्ज करें

आउटपुट को JSON में अनुवाद करें:

{ "author": "bob", "title": "this is my title", "tags": "fun"},
{ "author": "bob", "title": "this is my title", "tags": "good"},
{ "author": "bob", "title": "this is my title", "tags": "fun"}

क्योंकि हमने मानगो को "_id" फ़ील्ड को छोड़ने के लिए नहीं कहा था, इसलिए यह ऑटो-जोड़ा गया है।

कुंजी यह है कि एकत्रीकरण करने के लिए इसे टेबल की तरह बनाया जाए।


या इसके बारे में सोचने का दूसरा तरीका है UNION
Jeb50
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.