मैं MongoDB में SQL ज्वाइन समतुल्य कैसे करूं?


498

मैं MongoDB में SQL ज्वाइन समतुल्य कैसे करूं?

उदाहरण के लिए, आपके पास दो संग्रह (उपयोगकर्ता और टिप्पणियां) हैं और मैं सभी टिप्पणियों को pid ​​= 444 के साथ प्रत्येक के लिए उपयोगकर्ता जानकारी के साथ खींचना चाहता हूं।

comments
  { uid:12345, pid:444, comment="blah" }
  { uid:12345, pid:888, comment="asdf" }
  { uid:99999, pid:444, comment="qwer" }

users
  { uid:12345, name:"john" }
  { uid:99999, name:"mia"  }

क्या एक निश्चित क्षेत्र के साथ सभी टिप्पणियों को खींचने का एक तरीका है (उदाहरण के लिए ... खोज ({pid: 444})) और प्रत्येक टिप्पणी के साथ जुड़े उपयोगकर्ता की जानकारी एक बार में?

फिलहाल, मैं पहली बार उन टिप्पणियों को प्राप्त कर रहा हूं जो मेरे मानदंडों से मेल खाती हैं, फिर उस परिणाम सेट में सभी यूआईडी का पता लगा रहे हैं, उपयोगकर्ता ऑब्जेक्ट प्राप्त कर रहे हैं, और उन्हें टिप्पणी के परिणामों के साथ विलय कर रहे हैं। लगता है जैसे मैं गलत कर रहा हूं।


35
इस सवाल पर अंतिम उत्तर शायद सबसे अधिक प्रासंगिक है, क्योंकि MongoDB 3.2+ ने $ लुकिंग नामक एक ज्वाइन सॉल्यूशन लागू किया। सोचा था कि मैं इसे यहां धकेलूंगा क्योंकि शायद हर कोई नीचे तक नहीं पढ़ेगा। stackoverflow.com/a/33511166/2593330
Thefourtheye

6
सही, $ लुक्स MongoDB 3.2 में पेश किया गया था। विवरण docs.mongodb.org/master/reference/operator/aggregation/lookup/…
NDB

जवाबों:


306

मानगो 3.2 के अनुसार इस प्रश्न के उत्तर अधिकतर सही नहीं हैं। एकत्रीकरण पाइपलाइन में जोड़ा गया नया $ लुकअप ऑपरेटर अनिवार्य रूप से एक बाएं बाहरी जुड़ाव के समान है:

https://docs.mongodb.org/master/reference/operator/aggregation/lookup/#pipe._S_lookup

डॉक्स से:

{
   $lookup:
     {
       from: <collection to join>,
       localField: <field from the input documents>,
       foreignField: <field from the documents of the "from" collection>,
       as: <output array field>
     }
}

बेशक मानगो एक संबंधपरक डेटाबेस नहीं है, और देवता $ लुकिंग के लिए विशिष्ट उपयोग के मामलों की सिफारिश करने के लिए सावधानी बरत रहे हैं, लेकिन कम से कम 3.2 में शामिल होने के लिए अब मोंगोडीबी के साथ संभव है।


@ क्लेटन: दो और संग्रह के बारे में कैसे?
दीपन डेडानिया '

1
@DipenDedania सिर्फ एकत्रीकरण पाइपलाइन में अतिरिक्त $ लुकअप चरण जोड़ते हैं।
क्लेटन गुलिक

मैं सही संग्रह में अपनी इसी आईडी के साथ बाएँ संग्रह में सरणी में किसी भी क्षेत्र में शामिल नहीं कर सकता। किसी ने मेरी मदद की ??
प्रतीक सिंह

1
मैं इस बारे में थोड़ा भ्रमित हूं - क्या यह निर्दिष्ट करने का कोई तरीका है कि आप "से" संग्रह में केवल कुछ दस्तावेज़ चाहते हैं, या क्या यह स्वचालित रूप से एक ही बार में सभी में शामिल हो जाता है?
user3413723

बस अगर नवीनतम स्प्रिंग डेटा MongoDB 3.2 के लिए समर्थन है सोच रहा था?
गतवारी ३३३

142

आधिकारिक मोंगोडब साइट पर यह पृष्ठ इस प्रश्न को बिल्कुल संबोधित करता है :

https://mongodb-documentation.readthedocs.io/en/latest/ecosystem/tutorial/model-data-for-ruby-on-rails.html

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

संबंधपरक शुद्धतावादी पहले से ही असहज महसूस कर रहे होंगे, जैसे कि हम किसी सार्वभौमिक कानून का उल्लंघन कर रहे हों। लेकिन यह ध्यान रखें कि MongoDB संग्रह संबंधपरक तालिकाओं के बराबर नहीं हैं; प्रत्येक एक अद्वितीय डिजाइन उद्देश्य प्रदान करता है। एक सामान्यीकृत तालिका डेटा का एक परमाणु, अलग-थलग हिस्सा प्रदान करती है। एक दस्तावेज, हालांकि, अधिक बारीकी से एक पूरे के रूप में एक वस्तु का प्रतिनिधित्व करता है। एक सामाजिक समाचार साइट के मामले में, यह तर्क दिया जा सकता है कि एक उपयोगकर्ता नाम कहानी में पोस्ट किया जा रहा है।


51
@dudelgrincen यह सामान्यीकरण और संबंधपरक डेटाबेस से प्रतिमान बदलाव है। NoSQL का लक्ष्य बहुत जल्दी डेटाबेस से पढ़ना और लिखना है। BigData के साथ आपको एप्लिकेशन और फ्रंट एंड सर्वर के स्कैड्स के साथ DBs पर कम नंबर मिलने वाले हैं। आपसे उम्मीद की जाती है कि आप एक सेकंड में लाखों लेनदेन करें। डेटाबेस से भारी उठाने को उतार दें और आवेदन स्तर पर रख दें। यदि आपको गहन विश्लेषण की आवश्यकता है, तो आप एक एकीकरण कार्य चलाते हैं जो आपके डेटा को OLAP डेटाबेस में डालता है। आपको वैसे भी अपने ओएलटीपी डीबीएस से कई गहरे सवाल नहीं होने चाहिए।
स्नोबर्न्ट

18
@dudelgrincen मुझे यह भी कहना चाहिए कि यह हर प्रोजेक्ट या डिज़ाइन के लिए नहीं है। यदि आपके पास SQL ​​टाइप डेटाबेस में काम करने वाली कोई चीज़ है तो उसे क्यों बदलें? यदि आप noSQL के साथ काम करने के लिए अपने स्कीमा की मालिश नहीं कर सकते, तो नहीं।
स्नोबर्न्ट

9
माइग्रेशन और लगातार विकसित होने वाले स्कीमा भी NoSQL सिस्टम पर प्रबंधित करने के लिए बहुत आसान हैं।
जस्टिन

14
क्या होगा यदि उपयोगकर्ता के पास वेबसाइट में 3.540 पद हैं, और वह प्रोफ़ाइल में अपना उपयोगकर्ता नाम बदलता है? क्या हर पोस्ट को नए उपयोगकर्ता नाम के साथ अपडेट किया जाना चाहिए?
इवो ​​परेरा

2
@IvoPereira हां और यही कारण है कि किसी को इस तरह से मॉडलिंग डेटा से बचना चाहिए। एक लेख है जो एक ही परिदृश्य और उसके परिणामों की व्याख्या करता है: Why You should should Never Use MongoDB
Omid

138

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

.- लेखक:

db.authors.insert([
    {
        _id: 'a1',
        name: { first: 'orlando', last: 'becerra' },
        age: 27
    },
    {
        _id: 'a2',
        name: { first: 'mayra', last: 'sanchez' },
        age: 21
    }
]);

।- श्रेणियाँ:

db.categories.insert([
    {
        _id: 'c1',
        name: 'sci-fi'
    },
    {
        _id: 'c2',
        name: 'romance'
    }
]);

।- पुस्तकें

db.books.insert([
    {
        _id: 'b1',
        name: 'Groovy Book',
        category: 'c1',
        authors: ['a1']
    },
    {
        _id: 'b2',
        name: 'Java Book',
        category: 'c2',
        authors: ['a1','a2']
    },
]);

.- पुस्तक उधार

db.lendings.insert([
    {
        _id: 'l1',
        book: 'b1',
        date: new Date('01/01/11'),
        lendingBy: 'jose'
    },
    {
        _id: 'l2',
        book: 'b1',
        date: new Date('02/02/12'),
        lendingBy: 'maria'
    }
]);

।- जादू:

db.books.find().forEach(
    function (newBook) {
        newBook.category = db.categories.findOne( { "_id": newBook.category } );
        newBook.lendings = db.lendings.find( { "book": newBook._id  } ).toArray();
        newBook.authors = db.authors.find( { "_id": { $in: newBook.authors }  } ).toArray();
        db.booksReloaded.insert(newBook);
    }
);

.- नया संग्रह डेटा प्राप्त करें:

db.booksReloaded.find().pretty()

।- प्रतिक्रिया :)

{
    "_id" : "b1",
    "name" : "Groovy Book",
    "category" : {
        "_id" : "c1",
        "name" : "sci-fi"
    },
    "authors" : [
        {
            "_id" : "a1",
            "name" : {
                "first" : "orlando",
                "last" : "becerra"
            },
            "age" : 27
        }
    ],
    "lendings" : [
        {
            "_id" : "l1",
            "book" : "b1",
            "date" : ISODate("2011-01-01T00:00:00Z"),
            "lendingBy" : "jose"
        },
        {
            "_id" : "l2",
            "book" : "b1",
            "date" : ISODate("2012-02-02T00:00:00Z"),
            "lendingBy" : "maria"
        }
    ]
}
{
    "_id" : "b2",
    "name" : "Java Book",
    "category" : {
        "_id" : "c2",
        "name" : "romance"
    },
    "authors" : [
        {
            "_id" : "a1",
            "name" : {
                "first" : "orlando",
                "last" : "becerra"
            },
            "age" : 27
        },
        {
            "_id" : "a2",
            "name" : {
                "first" : "mayra",
                "last" : "sanchez"
            },
            "age" : 21
        }
    ],
    "lendings" : [ ]
}

मुझे उम्मीद है कि यह लाइनें आपकी मदद कर सकती हैं।


2
मैं सोच रहा हूँ कि क्या यह समान कोड सिद्धांत mongodb का उपयोग करके चलाया जा सकता है?
30'14

4
क्या होता है जब संदर्भ वस्तुओं में से एक को अपडेट मिलता है? क्या यह अद्यतन पुस्तक ऑब्जेक्ट में स्वचालित रूप से प्रतिबिंबित होता है? या उस पाश को फिर से चलाने की जरूरत है?
बैलून

14
यह तब तक ठीक है जब तक आपका डेटा छोटा है। यह आपके ग्राहक के लिए प्रत्येक पुस्तक सामग्री लाने जा रहा है और फिर प्रत्येक श्रेणी, उधार और लेखकों को एक-एक करके प्राप्त कर रहा है। जिस समय आपकी किताबें हजारों में होती हैं, यह वास्तव में बहुत धीमी गति से होता है। एक बेहतर तकनीक शायद एकत्रीकरण पाइपलाइन का उपयोग करना और एक अलग संग्रह में विलय किए गए डेटा का उत्पादन करना होगा। मुझे इसे फिर से वापस लाने के लिए। मैं एक जवाब जोड़ दूंगा।
संदीप गिरी

क्या आप अपने एल्गोरिथ्म को इस अन्य उदाहरण में ढाल सकते हैं? stackoverflow.com/q/32718079/287948
पीटर क्रस

1
@SandeepGiri मैं समग्र पाइपलाइन कैसे कर सकता हूं क्योंकि मेरे पास वास्तव में गहन डेटा है अलग संग्रह में शामिल होने की आवश्यकता है ??
यासीन अब्दुल-रहमान

38

आपको इसे आपके द्वारा बताए गए तरीके से करना होगा। MongoDB एक गैर-संबंधपरक डेटाबेस है और जॉइन का समर्थन नहीं करता है।


4
लगता है कि गलत प्रदर्शन एक sql सर्वर पृष्ठभूमि से आ रहा है, लेकिन इसकी शायद दस्तावेज़ db के साथ इतना बुरा नहीं है?
terjetyl

3
एक sql सर्वर बैकग्राउंड से, मैं एक बार में एक नई क्वेरी के लिए इनपुट के रूप में 'रिजल्ट सेट' (चुने हुए फ़ील्ड्स के साथ) के लिए MongoDB की सराहना करूँगा, बहुत कुछ SQL में नेस्टेड क्वेरीज़ की तरह है
Stijn Sanders

1
@terjetyl आपको वास्तव में इसके लिए योजना बनानी होगी। आप किन क्षेत्रों में आगे के छोर पर प्रस्तुत होने जा रहे हैं, यदि यह एक व्यक्तिगत दृष्टिकोण में एक सीमित राशि है तो आप उन्हें एम्बेडेड दस्तावेजों के रूप में लेते हैं। कुंजी को जुड़ने की आवश्यकता नहीं है। यदि आप गहन विश्लेषण करना चाहते हैं, तो आप इसे किसी अन्य डेटाबेस में तथ्य के बाद करते हैं। ऐसी नौकरी चलाएं जो डेटा को इष्टतम प्रदर्शन के लिए OLAP क्यूब में बदल दे।
स्नोबर्न्ट

4
मोंगो से 3.2 वर्जन लेफ्ट जॉइन सपोर्टेड हैं।
सोमनाथ मुलुक

18

जैसा कि अन्य लोगों ने बताया है कि आप किसी भी संबंधपरक डेटाबेस से एक संबंधपरक डेटाबेस बनाने की कोशिश कर रहे हैं, जिसे आप वास्तव में नहीं करना चाहते हैं, लेकिन वैसे भी, यदि आपके पास एक मामला है कि आपको यह करना है तो एक समाधान है जिसका आप उपयोग कर सकते हैं। हम पहले संग्रह A (या आपके मामले में उपयोगकर्ताओं) पर एक फ़ॉर्च खोजते हैं और फिर हमें प्रत्येक आइटम एक ऑब्जेक्ट के रूप में मिलता है, फिर हम अपने दूसरे संग्रह में (आपके मामले की टिप्पणियों में) देखने के लिए ऑब्जेक्ट प्रॉपर्टी (आपके मामले में यूआईडी) का उपयोग करते हैं यदि हम इसे पा सकते हैं फिर हमारे पास एक मैच है और हम इसके साथ कुछ प्रिंट या कर सकते हैं। आशा है कि यह आपकी मदद करता है और शुभकामनाएँ :)

db.users.find().forEach(
function (object) {
    var commonInBoth=db.comments.findOne({ "uid": object.uid} );
    if (commonInBoth != null) {
        printjson(commonInBoth) ;
        printjson(object) ;
    }else {
        // did not match so we don't care in this case
    }
});

क्या यह वह वस्तु नहीं है, जिस पर हम वर्तमान में लूपिंग कर रहे हैं?
स्कार्लिंस्की

18

$ लुकिंग , $ प्रोजेक्ट और $ मैच के सही संयोजन के साथ , आप कई मापदंडों पर म्यूटेंट टेबल में शामिल हो सकते हैं। ऐसा इसलिए है क्योंकि उन्हें कई बार जंजीर बनाया जा सकता है।

मान लीजिए हम निम्नलिखित करना चाहते हैं ( संदर्भ )

SELECT S.* FROM LeftTable S
LEFT JOIN RightTable R ON S.ID =R.ID AND S.MID =R.MID WHERE R.TIM >0 AND 
S.MOB IS NOT NULL

चरण 1: सभी तालिकाओं को लिंक करें

आप जितनी चाहें उतनी तालिकाओं को देख सकते हैं।

$ लुकअप - क्वेरी में प्रत्येक तालिका के लिए एक

$ खोलना - क्योंकि डेटा को सही ढंग से चिह्नित किया गया है, अन्यथा सरणियों में लिपटे हुए हैं

अजगर कोड ।।

db.LeftTable.aggregate([
                        # connect all tables

                        {"$lookup": {
                          "from": "RightTable",
                          "localField": "ID",
                          "foreignField": "ID",
                          "as": "R"
                        }},
                        {"$unwind": "R"}

                        ])

चरण 2: सभी शर्तों को परिभाषित करें

$ परियोजना : यहां सभी सशर्त विवरणों को परिभाषित करें, साथ ही वे सभी चर जिन्हें आप चुनना चाहते हैं।

अजगर कोड ।।

db.LeftTable.aggregate([
                        # connect all tables

                        {"$lookup": {
                          "from": "RightTable",
                          "localField": "ID",
                          "foreignField": "ID",
                          "as": "R"
                        }},
                        {"$unwind": "R"},

                        # define conditionals + variables

                        {"$project": {
                          "midEq": {"$eq": ["$MID", "$R.MID"]},
                          "ID": 1, "MOB": 1, "MID": 1
                        }}
                        ])

चरण 3: सभी शर्तों में शामिल हों

$ मैच - OR या AND आदि का उपयोग करके सभी शर्तों से जुड़ें। इनमें से कई गुण हो सकते हैं।

$ परियोजना : सभी शर्तों को अपरिभाषित करें

अजगर कोड ।।

db.LeftTable.aggregate([
                        # connect all tables

                        {"$lookup": {
                          "from": "RightTable",
                          "localField": "ID",
                          "foreignField": "ID",
                          "as": "R"
                        }},
                        {"$unwind": "$R"},

                        # define conditionals + variables

                        {"$project": {
                          "midEq": {"$eq": ["$MID", "$R.MID"]},
                          "ID": 1, "MOB": 1, "MID": 1
                        }},

                        # join all conditionals

                        {"$match": {
                          "$and": [
                            {"R.TIM": {"$gt": 0}}, 
                            {"MOB": {"$exists": True}},
                            {"midEq": {"$eq": True}}
                        ]}},

                        # undefine conditionals

                        {"$project": {
                          "midEq": 0
                        }}

                        ])

टेबल, कंडिशन और जॉइन के किसी भी तरह से बहुत कुछ इस तरह से किया जा सकता है।


17

यहाँ "जॉइन" * एक्टर्स और मूवीज़ कलेक्शन का एक उदाहरण है :

https://github.com/mongodb/cookbook/blob/master/content/patterns/pivot.txt

यह .mapReduce()विधि का उपयोग करता है

* join - डॉक्यूमेंट-ओरिएंटेड डेटाबेस में शामिल होने का विकल्प


19
-1, यह दो संग्रह से डेटा में शामिल नहीं है। यह एक एकल संग्रह (अभिनेताओं) के डेटा का उपयोग कर डेटा को चारों ओर से घूम रहा है। ताकि चीजें जो किज थीं वो अब वैल्यू हैं और वैल्यू अब की हैं ... जॉइन से बहुत अलग।
इवान टेरान

12
यह वही है जो आपको करना है, MongoDB संबंधपरक नहीं है लेकिन दस्तावेज़ उन्मुख है। MapReduce बड़े प्रदर्शन के साथ डेटा के साथ खेलने की अनुमति देता है (आप क्लस्टर आदि का उपयोग कर सकते हैं ....) लेकिन साधारण मामलों के लिए भी, यह बहुत उपयोगी है!
थॉमस डेकाक्स

14

आप लुकआउट का उपयोग करके मानगो में दो संग्रह में शामिल हो सकते हैं जो 3.2 संस्करण में पेश किया गया है। आपके मामले में क्वेरी होगी

db.comments.aggregate({
    $lookup:{
        from:"users",
        localField:"uid",
        foreignField:"uid",
        as:"users_comments"
    }
})

या आप उपयोगकर्ताओं के संबंध में भी शामिल हो सकते हैं तो नीचे दिए गए अनुसार थोड़ा परिवर्तन होगा।

db.users.aggregate({
    $lookup:{
        from:"comments",
        localField:"uid",
        foreignField:"uid",
        as:"users_comments"
    }
})

यह SQL में लेफ्ट और राइट जॉइन की तरह ही काम करेगा।


11

यह इस बात पर निर्भर करता है कि आप क्या करने की कोशिश कर रहे हैं।

आपने वर्तमान में इसे एक सामान्यीकृत डेटाबेस के रूप में स्थापित किया है, जो ठीक है, और जिस तरह से आप कर रहे हैं वह उपयुक्त है।

हालाँकि, इसे करने के अन्य तरीके भी हैं।

आपके पास एक पोस्ट संग्रह हो सकता है जिसमें उपयोगकर्ताओं के संदर्भ में प्रत्येक पोस्ट के लिए टिप्पणियों को imbedded किया गया है जिसे आप पाने के लिए पुनरावृत्त क्वेरी कर सकते हैं। आप टिप्पणियों के साथ उपयोगकर्ता के नाम को संग्रहीत कर सकते हैं, आप उन सभी को एक दस्तावेज़ में संग्रहीत कर सकते हैं।

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

NoSQL के साथ, यदि आप स्वीकार करते हैं कि अतिरेक और भंडारण स्थान उनकी लागत के कारण समस्याएँ नहीं हैं (दोनों अतिरिक्त समय में अतिरिक्त डेटा संग्रहीत करने के लिए अद्यतन और हार्ड ड्राइव की लागत की आवश्यकता होती है), असामान्यता एक मुद्दा नहीं है (एम्बेडेड सरणियों के लिए) सैकड़ों आइटम यह एक प्रदर्शन मुद्दा हो सकता है, लेकिन ज्यादातर समय यह समस्या नहीं है)। इसके अतिरिक्त आपके पास हर डेटाबेस क्लस्टर के लिए कई एप्लिकेशन और फ्रंट एंड सर्वर होंगे। उन्हें ज्वाइन करने की भारी उठाने की कोशिस करें और डेटाबेस सर्वर को पढ़ने और लिखने से चिपके रहने दें।

TL; DR: आप जो कर रहे हैं वह ठीक है, और इसे करने के अन्य तरीके भी हैं। कुछ महान उदाहरणों के लिए मोंगोडब प्रलेखन के डेटा मॉडल पैटर्न देखें। http://docs.mongodb.org/manual/data-modeling/


8
"सामान्यीकरण अंतरिक्ष को बचाने की कोशिश करने की अवधारणा से आता है" मैं यह सवाल करता हूं। IMHO सामान्यीकरण अतिरेक से बचने की अवधारणा से आता है। मान लें कि आप एक उपयोगकर्ता का नाम ब्लॉगपोस्ट के साथ संग्रहीत करते हैं। क्या होगा अगर वह शादी करती है? एक सामान्यीकृत मॉडल में आपको सभी पदों के माध्यम से उतारा नहीं जाएगा और नाम बदलना होगा। एक सामान्यीकृत मॉडल में आप आमतौर पर वन रिकॉर्ड को बदलते हैं।
डैनियलखान

@DanielKhan अतिरेक को रोकना और अंतरिक्ष को बचाना समान अवधारणाएं हैं, लेकिन पुन: विश्लेषण पर मैं सहमत हूं, अतिरेक इस डिजाइन का मूल कारण है। मैं पुनर्जन्म लूंगा। नोट के लिए धन्यवाद।
स्नोवबर्न

11

एक विनिर्देश है कि बहुत सारे ड्राइवर समर्थन करते हैं जिन्हें DBRef कहा जाता है।

दस्तावेजों के बीच संदर्भ बनाने के लिए DBRef एक अधिक औपचारिक विनिर्देश है। DBRefs (आम तौर पर) में संग्रह नाम के साथ-साथ ऑब्जेक्ट आईडी भी शामिल है। अधिकांश डेवलपर्स केवल डीबीआरएफ का उपयोग करते हैं यदि संग्रह एक दस्तावेज़ से अगले में बदल सकता है। यदि आपका संदर्भित संग्रह हमेशा समान रहेगा, तो ऊपर उल्लिखित मैन्युअल संदर्भ अधिक कुशल हैं।

MongoDB प्रलेखन से लिया गया: डेटा मॉडल> ​​डेटा मॉडल संदर्भ> डेटाबेस संदर्भ


11

$ लुकअप (एकत्रीकरण)

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

समानता मैच

"ज्वाइन" संग्रह के दस्तावेज़ों से फ़ील्ड के साथ इनपुट दस्तावेज़ों के क्षेत्र के बीच एक समानता मैच करने के लिए, $ लुकअप चरण में निम्न सिंटैक्स है:

{
   $lookup:
     {
       from: <collection to join>,
       localField: <field from the input documents>,
       foreignField: <field from the documents of the "from" collection>,
       as: <output array field>
     }
}

ऑपरेशन निम्नलिखित छद्म-एसक्यूएल कथन के अनुरूप होगा:

SELECT *, <output array field>
FROM collection
WHERE <output array field> IN (SELECT <documents as determined from the pipeline>
                               FROM <collection to join>
                               WHERE <pipeline> );

मानगो यूआरएल


उप-क्वेरी जुड़ने की तुलना में पूरी तरह से अलग है, यदि आपकी बाईं ओर की मेज विशाल है, तो उप-क्वेरी का मतलब है कि प्रत्येक पंक्ति को एक क्वेरी खुद करनी होगी। यह बहुत धीमा हो जाएगा। sql में join बहुत तेज है।
yww325

8

3.2.6 से पहले , Mongodb mysql की तरह क्वेरी से जुड़ने का समर्थन नहीं करता है। नीचे समाधान जो आपके लिए काम करता है।

 db.getCollection('comments').aggregate([
        {$match : {pid : 444}},
        {$lookup: {from: "users",localField: "uid",foreignField: "uid",as: "userData"}},
   ])


3

MongoDB जुड़ने की अनुमति नहीं देता है, लेकिन आप इसे संभालने के लिए प्लगइन्स का उपयोग कर सकते हैं। Mongo-join प्लगइन की जाँच करें। यह सबसे अच्छा है और मैं पहले ही इसका इस्तेमाल कर चुका हूं। आप इसे इस तरह सीधे npm का उपयोग करके स्थापित कर सकते हैं npm install mongo-join। आप उदाहरणों के साथ पूर्ण दस्तावेज़ देख सकते हैं

(++) वास्तव में उपयोगी उपकरण जब हमें (एन) संग्रह में शामिल होने की आवश्यकता होती है

(-) हम क्वेरी के शीर्ष स्तर पर स्थितियां लागू कर सकते हैं

उदाहरण

var Join = require('mongo-join').Join, mongodb = require('mongodb'), Db = mongodb.Db, Server = mongodb.Server;
db.open(function (err, Database) {
    Database.collection('Appoint', function (err, Appoints) {

        /* we can put conditions just on the top level */
        Appoints.find({_id_Doctor: id_doctor ,full_date :{ $gte: start_date },
            full_date :{ $lte: end_date }}, function (err, cursor) {
            var join = new Join(Database).on({
                field: '_id_Doctor', // <- field in Appoints document
                to: '_id',         // <- field in User doc. treated as ObjectID automatically.
                from: 'User'  // <- collection name for User doc
            }).on({
                field: '_id_Patient', // <- field in Appoints doc
                to: '_id',         // <- field in User doc. treated as ObjectID automatically.
                from: 'User'  // <- collection name for User doc
            })
            join.toArray(cursor, function (err, joinedDocs) {

                /* do what ever you want here */
                /* you can fetch the table and apply your own conditions */
                .....
                .....
                .....


                resp.status(200);
                resp.json({
                    "status": 200,
                    "message": "success",
                    "Appoints_Range": joinedDocs,


                });
                return resp;


            });

    });

2

आप इसे एकत्रीकरण पाइपलाइन का उपयोग कर सकते हैं, लेकिन इसे स्वयं लिखने के लिए एक दर्द है।

आप mongo-join-queryअपनी क्वेरी से स्वचालित रूप से एकत्रीकरण पाइपलाइन बनाने के लिए उपयोग कर सकते हैं ।

इस तरह आपकी क्वेरी दिखाई देगी:

const mongoose = require("mongoose");
const joinQuery = require("mongo-join-query");

joinQuery(
    mongoose.models.Comment,
    {
        find: { pid:444 },
        populate: ["uid"]
    },
    (err, res) => (err ? console.log("Error:", err) : console.log("Success:", res.results))
);

आपके परिणाम में uidफ़ील्ड में उपयोगकर्ता ऑब्जेक्ट होगा और आप जितना चाहें उतना गहरा स्तर जोड़ सकते हैं। आप उपयोगकर्ता के संदर्भ को पॉप्युलेट कर सकते हैं, जो एक टीम का संदर्भ बनाता है, जो कुछ और आदि का संदर्भ बनाता है।

अस्वीकरण : मैंने mongo-join-queryइस सटीक समस्या से निपटने के लिए लिखा था ।


0

playORM आपके लिए S-SQL (स्केलेबल SQL) का उपयोग करके कर सकता है जो कि विभाजन को ऐसे जोड़ता है कि आप विभाजन में शामिल हो सकते हैं।


-2

नहीं, ऐसा नहीं लगता कि आप इसे गलत कर रहे हैं। MongoDB जॉइन "क्लाइंट साइड" हैं। बहुत अच्छा लगा जैसे आपने कहा:

फिलहाल, मैं पहली बार उन टिप्पणियों को प्राप्त कर रहा हूं जो मेरे मानदंडों से मेल खाती हैं, फिर उस परिणाम सेट में सभी यूआईडी का पता लगा रहे हैं, उपयोगकर्ता ऑब्जेक्ट प्राप्त कर रहे हैं, और उन्हें टिप्पणी के परिणामों के साथ विलय कर रहे हैं। लगता है जैसे मैं गलत कर रहा हूं।

1) Select from the collection you're interested in.
2) From that collection pull out ID's you need
3) Select from other collections
4) Decorate your original results.

यह एक "वास्तविक" में शामिल नहीं है, लेकिन यह वास्तव में SQL जॉइन की तुलना में अधिक उपयोगी है क्योंकि आपको मूल रूप से चयनित सेट को सजाने के बजाय "कई" पक्षीय जोड़ के लिए डुप्लिकेट पंक्तियों से निपटना नहीं है।

इस पेज पर बकवास और FUD का एक बहुत कुछ है। 5 साल बाद मुड़ता है MongoDB अभी भी एक बात है।


"आपको" कई "पक्षीय जुड़ावों के लिए डुप्लिकेट पंक्तियों से निपटने की ज़रूरत नहीं है" - इससे आपको कोई मतलब नहीं है। क्या आप स्पष्ट कर सकते हो?
मार्क अमेरी सिप

1
@ मार्की, निश्चित। SQL में एक nn संबंध डुप्लिकेट पंक्तियों को लौटाएगा। जैसे मित्र। अगर बॉब मेरी और जेन के दोस्त हैं, तो आपको बॉब, बॉब, मैरी और बॉब, जेन के लिए 2 पंक्तियाँ मिलेंगी। 2 बोबस एक झूठ है, केवल एक बॉब है। क्लाइंट-साइड जॉइन के साथ आप बॉब से शुरू कर सकते हैं और सजा सकते हैं कि आप कैसे पसंद करते हैं: बॉब, "मैरी और जेन"। एसक्यूएल चलो आप सबक्वेरीज के साथ ऐसा करते हैं, लेकिन यह डीबी सर्वर पर काम कर रहा है जो क्लाइंट पर किया जा सकता है।
माइकल कोल

-3

मुझे लगता है, अगर आपको सामान्यीकृत डेटा तालिकाओं की आवश्यकता है - आपको कुछ अन्य डेटाबेस समाधानों की कोशिश करने की आवश्यकता है।

लेकिन मुझे लगता है कि गिट पर MOngo के लिए कि sollution , आवेषण कोड में - यह फिल्म का नाम है, लेकिन noi फिल्म की आईडी

मुसीबत

आपके पास उन फ़िल्मों की एक सरणी के साथ अभिनेताओं का एक संग्रह है जो उन्होंने किया है।

आप प्रत्येक में अभिनेताओं की एक सरणी के साथ फिल्मों का एक संग्रह उत्पन्न करना चाहते हैं।

कुछ सैंपल डेटा

 db.actors.insert( { actor: "Richard Gere", movies: ['Pretty Woman', 'Runaway Bride', 'Chicago'] });
 db.actors.insert( { actor: "Julia Roberts", movies: ['Pretty Woman', 'Runaway Bride', 'Erin Brockovich'] });

समाधान

हमें एक्टर डॉक्यूमेंट में प्रत्येक मूवी के माध्यम से लूप करने की जरूरत है और प्रत्येक मूवी को व्यक्तिगत रूप से फेंकना है।

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

कोड
map = function() {
  for(var i in this.movies){
    key = { movie: this.movies[i] };
    value = { actors: [ this.actor ] };
    emit(key, value);
  }
}

reduce = function(key, values) {
  actor_list = { actors: [] };
  for(var i in values) {
    actor_list.actors = values[i].actors.concat(actor_list.actors);
  }
  return actor_list;
}

ध्यान दें कि कैसे एक्टर_लिस्ट वास्तव में एक जावास्क्रिप्ट ऑब्जेक्ट है जिसमें एक सरणी होती है। यह भी ध्यान रखें कि मानचित्र समान संरचना का उत्सर्जन करता है।

नक्शे को निष्पादित / कम करने के लिए निम्न को चलाएँ, इसे "पिवट" संग्रह में आउटपुट करें और परिणाम प्रिंट करें:

प्रिंटजसन (db.actors.mapReduce (नक्शा, घटाना, "पिवट")); db.pivot.find () foreach (printjson)।

यहाँ नमूना आउटपुट है, ध्यान दें कि "सुंदर महिला" और "रनवे ब्राइड" में "रिचर्ड गेरे" और "जूलिया रॉबर्ट्स" दोनों हैं।

{ "_id" : { "movie" : "Chicago" }, "value" : { "actors" : [ "Richard Gere" ] } }
{ "_id" : { "movie" : "Erin Brockovich" }, "value" : { "actors" : [ "Julia Roberts" ] } }
{ "_id" : { "movie" : "Pretty Woman" }, "value" : { "actors" : [ "Richard Gere", "Julia Roberts" ] } }
{ "_id" : { "movie" : "Runaway Bride" }, "value" : { "actors" : [ "Richard Gere", "Julia Roberts" ] } }


ध्यान दें कि इस उत्तर की सामग्री (अर्थात अंग्रेजी में जो बिट थोड़ी है) को मोंटबीडी कुकबुक से गीथहब लिंक पर दिए गए उत्तरदाता को कॉपी किया गया है।
मार्क अमेरी

-4

हम mongoDB उप क्वेरी का उपयोग करके दो संग्रह को मर्ज कर सकते हैं। यहाँ उदाहरण है, टिप्पणियाँ--

`db.commentss.insert([
  { uid:12345, pid:444, comment:"blah" },
  { uid:12345, pid:888, comment:"asdf" },
  { uid:99999, pid:444, comment:"qwer" }])`

Userss--

db.userss.insert([
  { uid:12345, name:"john" },
  { uid:99999, name:"mia"  }])

JOIN-- के लिए MongoDB उप क्वेरी -

`db.commentss.find().forEach(
    function (newComments) {
        newComments.userss = db.userss.find( { "uid": newComments.uid } ).toArray();
        db.newCommentUsers.insert(newComments);
    }
);`

नव निर्मित संग्रह से परिणाम प्राप्त करें--

db.newCommentUsers.find().pretty()

परिणाम--

`{
    "_id" : ObjectId("5511236e29709afa03f226ef"),
    "uid" : 12345,
    "pid" : 444,
    "comment" : "blah",
    "userss" : [
        {
            "_id" : ObjectId("5511238129709afa03f226f2"),
            "uid" : 12345,
            "name" : "john"
        }
    ]
}
{
    "_id" : ObjectId("5511236e29709afa03f226f0"),
    "uid" : 12345,
    "pid" : 888,
    "comment" : "asdf",
    "userss" : [
        {
            "_id" : ObjectId("5511238129709afa03f226f2"),
            "uid" : 12345,
            "name" : "john"
        }
    ]
}
{
    "_id" : ObjectId("5511236e29709afa03f226f1"),
    "uid" : 99999,
    "pid" : 444,
    "comment" : "qwer",
    "userss" : [
        {
            "_id" : ObjectId("5511238129709afa03f226f3"),
            "uid" : 99999,
            "name" : "mia"
        }
    ]
}`

आशा है कि इससे मदद मिलेगी।


7
आपने मूल रूप से लगभग एक समान, एक वर्षीय उत्तर की नकल क्यों की? stackoverflow.com/a/22739813/4186945
हैकेल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.