MongoDB कई-से-कई एसोसिएशन


143

आप MongoDB के साथ कई-से-कई सहयोग कैसे करेंगे?

उदाहरण के लिए; मान लीजिए कि आपके पास एक उपयोगकर्ता तालिका और एक रोल्स तालिका है। उपयोगकर्ताओं के पास कई भूमिकाएँ हैं, और भूमिकाओं के कई उपयोगकर्ता हैं। SQL भूमि में आप एक उपयोगकर्ता तालिका बना सकते हैं।

Users:
    Id
    Name

Roles:
    Id
    Name

UserRoles:
    UserId
    RoleId

MongoDB में रिश्ते को किस तरह से संभाला जाता है?


जवाबों:


96

अपनी क्वेरी की ज़रूरतों के आधार पर आप उपयोगकर्ता दस्तावेज़ में सब कुछ डाल सकते हैं:

{name:"Joe"
,roles:["Admin","User","Engineer"]
}

सभी इंजीनियर प्राप्त करने के लिए, का उपयोग करें:

db.things.find( { roles : "Engineer" } );

यदि आप अलग-अलग दस्तावेज़ों में भूमिकाएँ बनाए रखना चाहते हैं, तो आप दस्तावेज़ के _id को नाम के बजाय भूमिकाओं की सरणी में शामिल कर सकते हैं:

{name:"Joe"
,roles:["4b5783300334000000000aa9","5783300334000000000aa943","6c6793300334001000000006"]
}

और भूमिकाओं की तरह सेट करें:

{_id:"6c6793300334001000000006"
,rolename:"Engineer"
}

7
उत्तरार्द्ध बेहतर होगा क्योंकि मुझे सभी उपलब्ध भूमिकाओं की सूची प्राप्त करने की आवश्यकता है। एकमात्र बुरा हिस्सा मुझे तब एसोसिएशन के दोनों सिरों को स्थापित करने की आवश्यकता है। SQL तरीके से करते समय, UserRole को जोड़ने से उपयोगकर्ता को भूमिका के बारे में पता चल जाएगा और भूमिका उपयोगकर्ता के बारे में जान जाएगी। इस तरह से इसका मतलब है कि मुझे उपयोगकर्ता पर भूमिका और उपयोगकर्ता को भूमिका पर सेट करना होगा। मुझे लगता है कि हालांकि ठीक है।
जोश करीब

46
सिर्फ इसलिए कि एक डेटाबेस एसक्यूएल का समर्थन नहीं करता है इसका मतलब यह नहीं है कि संदर्भ उपयोगी उपकरण नहीं हैं NoSQL! = NoReference इस विवरण को देखें: mongodb.org/display/DOCS/Schema+Design
टॉम

8
यह एक अच्छा विचार नहीं लगता है। यदि आपके पास केवल छह भूमिकाएँ हैं, तो सुनिश्चित करें, लेकिन क्या होगा यदि आपके पास 20000 वस्तुएं हैं जो 20000 अधिक वस्तुओं (कई-कई संबंधों में) से जुड़ी हो सकती हैं? यहां तक ​​कि MongoDB डॉक्स संकेत देता है कि आपको संदर्भों के परस्पर, विशाल सरणियों से बचना चाहिए। docs.mongodb.org/manual/tutorial/…
CaptSaltyJack 20

स्पष्ट रूप से बहुत सी वस्तुओं के साथ कई-से-कई रिश्तों के लिए आप एक अलग समाधान का उपयोग करना चाहते हैं (जैसे डॉक्स में प्रकाशक / पुस्तक उदाहरण)। इस मामले में यह ठीक काम करता है और यदि आप अलग-अलग उपयोगकर्ता-भूमिका दस्तावेज़ बनाते हैं तो यह केवल जटिल होगा।
मृत्युंजय

1
यह अधिकांश प्रणालियों के लिए काम करता है coz भूमिकाओं आमतौर पर एक छोटा सा सेट है और हम आम तौर पर एक उपयोगकर्ता लेते हैं और फिर उसकी भूमिकाओं को देखते हैं। लेकिन अगर भूमिकाएं बड़ी हैं तो क्या होगा? या क्या होगा यदि मैं आपको उन उपयोगकर्ताओं की सूची देने के लिए कहूं जिनकी भूमिका है == "इंजीनियर"? अब आपको अपने संपूर्ण उपयोगकर्ताओं के संग्रह (उन सभी उपयोगकर्ताओं का दौरा करना होगा, जिनकी भूमिका अभियंता के रूप में अच्छी तरह से नहीं है) केवल 2 या 3 उपयोगकर्ता प्राप्त करने के लिए, जिनके पास उदाहरण के लिए ऐसे उपयोगकर्ताओं के बीच यह भूमिका हो सकती है। एक अलग तालिका या संग्रह बहुत बेहतर है।
theprogrammer

32

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

उदाहरण के लिए, "Roles में उपयोगकर्ता" डोमेन का उपयोग करता है:

  1. भूमिका - बनाएँ, पढ़ें, अपडेट, हटाएं, सूची उपयोगकर्ता, उपयोगकर्ता जोड़ें, उपयोगकर्ता निकालें, सभी उपयोगकर्ताओं को साफ़ करें, उपयोगकर्ता का सूचकांक या "इस उपयोगकर्ता इन रोल" का समर्थन करने के लिए इसी तरह (एक कंटेनर + अपने स्वयं के मेटाडेटा जैसे संचालन)।
  2. उपयोगकर्ता - बनाएँ, पढ़ें, अपडेट करें, हटाएं (एक स्वतंत्र इकाई की तरह CRUD ऑपरेशन)

इसे निम्नलिखित दस्तावेज़ टेम्प्लेट के रूप में तैयार किया जा सकता है:

User: { _id: UniqueId, name: string, roles: string[] }
    Indexes: unique: [ name ]
Role: { _id: UniqueId, name: string, users: string[] }
    Indexes: unique: [ name ]

उपयोगकर्ता इकाई से भूमिका-संबंधित सुविधाओं जैसे उच्च आवृत्ति उपयोगों का समर्थन करने के लिए, उपयोगकर्ता। उपयोगकर्ता जानबूझकर नामांकित किए जाते हैं, उपयोगकर्ता के साथ-साथ डुप्लिकेट संग्रहण वाले रोल.उज़र को संग्रहीत किया जाता है।

यदि यह पाठ में स्पष्ट रूप से स्पष्ट नहीं है, लेकिन दस्तावेज़ रिपॉजिटरी का उपयोग करते समय इस प्रकार की सोच को प्रोत्साहित किया जाता है।

मुझे उम्मीद है कि यह ऑपरेशन के रीड साइड के संबंध में अंतर को पाटने में मदद करता है।

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

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

ऑपरेशन जो वास्तव में हमारे परमाणु लेखन को ताले से बचाता है, एक भूमिका को साफ कर रहा है, जिसके परिणामस्वरूप User.roles सरणी से Role.name को हटाने के लिए कई उपयोगकर्ता अपडेट होंगे। स्पष्ट के इस ऑपरेशन को आम तौर पर हतोत्साहित किया जाता है, लेकिन यदि आवश्यक हो तो संचालन को आदेश देकर लागू किया जा सकता है:

  1. Role.users से उपयोगकर्ता नामों की सूची प्राप्त करें।
  2. चरण 1 से उपयोगकर्ता नामों को मिटाएं, User.roles से भूमिका नाम हटा दें।
  3. भूमिका साफ़ करें।

किसी समस्या के मामले में, जो चरण 2 के भीतर होने की सबसे अधिक संभावना है, एक रोलबैक आसान है क्योंकि चरण 1 से उपयोगकर्ता नामों का एक ही सेट पुनर्प्राप्त करने या जारी रखने के लिए उपयोग किया जा सकता है।


15

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

टिप्पणीकारों में से एक ने सावधानीपूर्वक रवैया अपनाया कि "यदि डेटा संबंधपरक है, तो रिलेशनल का उपयोग करें"। हालांकि, यह टिप्पणी केवल संबंधपरक दुनिया में समझ में आती है, जहां स्कीमा हमेशा आवेदन से पहले आते हैं।

विश्वसनीय विश्व: संरचना डेटा> इसे प्राप्त करने के लिए एप्लिकेशन लिखें
NOSQL वर्ल्ड: डिज़ाइन एप्लिकेशन> संरचना डेटा तदनुसार

भले ही डेटा रिलेशनल हो, NoSQL अभी भी एक विकल्प है। उदाहरण के लिए, एक-से-कई रिश्तों को कोई समस्या नहीं है और वे MongoDB डॉक्स में व्यापक रूप से शामिल हैं

एक 2010 समाधान के लिए एक 2015 समाधान

चूँकि यह प्रश्न पोस्ट किया गया था, इसलिए एसक्यूएल को एसक्यूएल के करीब लाने के गंभीर प्रयास हुए हैं। कैलिफोर्निया विश्वविद्यालय (सैन डिएगो) में यानिस पापकोनस्टेंटिनौ के नेतृत्व में टीम फॉरवर्ड पर काम कर रही है , जो SQL ++ का कार्यान्वयन है जो जल्द ही यहां पोस्ट की गई लगातार समस्याओं का समाधान हो सकता है।

अधिक व्यावहारिक स्तर पर, काउचबेस 4.0 की रिलीज़ का मतलब है कि, आप पहली बार NoSQL में मूल JOIN कर सकते हैं। वे अपने स्वयं के N1QL का उपयोग करते हैं। यह JOINउनके ट्यूटोरियल से एक उदाहरण है :

SELECT usr.personal_details, orders 
        FROM users_with_orders usr 
            USE KEYS "Elinor_33313792" 
                JOIN orders_with_users orders 
                    ON KEYS ARRAY s.order_id FOR s IN usr.shipped_order_history END

N1QL अधिकांश के लिए अनुमति देता है अगर नहीं सभी एसग्रेग्रेगेशन, फ़िल्टरिंग आदि सहित एसक्यूएल संचालन।

एसओ-न्यू हाईब्रिड समाधान नहीं

यदि MongoDB अभी भी एकमात्र विकल्प है, तो मैं अपने बिंदु पर वापस जाना चाहूंगा कि एप्लिकेशन को डेटा की संरचना पर पूर्वता लेना चाहिए। कोई भी जवाब हाइब्रिड एम्बेडिंग का उल्लेख नहीं करता है, जिसके तहत अधिकांश क्वेरिड डेटा को दस्तावेज़ / ऑब्जेक्ट में एम्बेड किया जाता है, और मामलों की अल्पसंख्यक के लिए संदर्भ रखे जाते हैं।

उदाहरण: जानकारी (भूमिका नाम के अलावा) प्रतीक्षा कर सकते हैं? उपयोगकर्ता को अभी तक किसी भी चीज की आवश्यकता नहीं है, जो कुछ भी अनुरोध नहीं करने से एप्लिकेशन बूटस्ट्रैपिंग तेज हो सकता है?

यह मामला हो सकता है अगर उपयोगकर्ता लॉग इन करता है और उसे सभी भूमिकाओं के लिए सभी विकल्पों को देखने की जरूरत होती है। हालांकि, उपयोगकर्ता एक "इंजीनियर" है और इस भूमिका के लिए विकल्प शायद ही कभी उपयोग किए जाते हैं। इसका मतलब यह है कि आवेदन केवल एस / वह उन पर क्लिक करना चाहता है के लिए एक इंजीनियर के लिए विकल्प दिखाने की जरूरत है।

यह एक दस्तावेज के साथ प्राप्त किया जा सकता है जो शुरू में आवेदन को बताता है (1) जो उपयोगकर्ता को भूमिका देता है (2) जहां एक विशेष भूमिका से जुड़े किसी घटना के बारे में जानकारी प्राप्त करना है।

   {_id: ObjectID(),
    roles: [[“Engineer”, ObjectId()”],
            [“Administrator”, ObjectId()”]]
   }

या, और भी बेहतर, भूमिकाओं के संग्रह में role.name फ़ील्ड को अनुक्रमणित करें, और आपको ऑब्जेक्ट () को एम्बेड करने की आवश्यकता नहीं हो सकती है।

एक और उदाहरण: सभी भूमिकाओं के बारे में जानकारी हर समय अनुरोध की जाती है?

यह भी हो सकता है कि उपयोगकर्ता डैशबोर्ड में प्रवेश करता है और 90% समय "इंजीनियर" की भूमिका से जुड़े कार्यों को करता है। हाइब्रिड एम्बेडिंग उस विशेष भूमिका के लिए पूरी तरह से किया जा सकता है और केवल बाकी के लिए संदर्भ रख सकता है।

{_id: ObjectID(),
  roles: [{name: Engineer”, 
           property1: value1,
           property2: value2
          },   
          [“Administrator”, ObjectId()”]
         ]
}

स्कीमलेस होना सिर्फ NoSQL की विशेषता नहीं है, यह इस मामले में एक फायदा हो सकता है। यह उपयोगकर्ता ऑब्जेक्ट की "भूमिका" संपत्ति में विभिन्न प्रकार की वस्तुओं को घोंसले के लिए पूरी तरह से मान्य है।


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