2016-11-10 7 views
10

में संग्रह पर रिकर्सिव खोज मेरे पास पेड़ संरचना के साथ मोंगोडीबी में दस्तावेजों की एक सूची है, जहां Model Tree Structures with Parent References पैटर्न का उपयोग किया जाता है। मैं एक एकल समेकन क्वेरी चाहता हूं जो 'नाम' संपत्ति को देखते हुए पूर्वजों की सूची (रूट तक) लौटाता है।MongoDB

संरचना:

{ 
    '_id': '1', 
    'name': 'A', 
    'parent': '', 
}, 
{ 
    '_id': '2', 
    'name': 'B', 
    'parent': 'A', 
}, 
{ 
    '_id': '3', 
    'name': 'C', 
    'parent': 'B', 
}, 
{ 
    '_id': '4', 
    'name': 'D', 
    'parent': 'C', 
} 

एकत्रीकरण परिणाम: (को देखते हुए नाम = 'डी')

{ 
    '_id': '4', 
    'name': 'D', 
    'ancestors': [{name:'C'}, {name:'B'}, {name:'A'}] 
} 

Note: मैं अब दस्तावेज़ संरचना बदल नहीं सकते। इससे कई समस्याएं पैदा होंगी। मैंने कई समाधान देखा जो Model Tree Structures with an Array of Ancestors का उपयोग करने का सुझाव देते हैं। लेकिन अब मैं इसका इस्तेमाल नहीं कर सकता। एकल समेकन क्वेरी का उपयोग कर उपर्युक्त पैटर्न के साथ इसे प्राप्त करने का कोई तरीका है? धन्यवाद

+0

'_id' स्ट्रिंग क्यों है? – styvane

+0

@Styvane यह सिर्फ एक उदाहरण है। वास्तविक दस्तावेज़ में ऑब्जेक्ट आईडी – RaR

+0

@RaR होगा स्टीवन के उत्तर के बारे में कुछ ऐसा है जो आपके लिए काम नहीं करता है जो बक्षीस को प्रेरित करता है? – JohnnyHK

उत्तर

11

मोंगोडीबी 3.4 से शुरू, हम इसे एकत्रीकरण फ्रेमवर्क के साथ कर सकते हैं।

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

पाइप लाइन में अगले चरण $match मंच है जहाँ हम बस "नाम" का चयन करें हम में रुचि रखते हैं है।

अंतिम चरण $addFields या $project मंच है जहाँ हम "पूर्वजों" करने के लिए एक अभिव्यक्ति लागू है $map सरणी ऑपरेटर का उपयोग कर सरणी।

बेशक $reverseArray ऑपरेटर के साथ हम reverse our array अपेक्षित परिणाम प्राप्त करने के लिए।

db.collection.aggregate(
    [ 
     { "$graphLookup": { 
      "from": "collection", 
      "startWith": "$parent", 
      "connectFromField": "parent", 
      "connectToField": "name", 
      "as": "ancestors" 
     }}, 
     { "$match": { "name": "D" } }, 
     { "$addFields": { 
      "ancestors": { 
       "$reverseArray": { 
        "$map": { 
         "input": "$ancestors", 
         "as": "t", 
         "in": { "name": "$$t.name" } 
        } 
       } 
      } 
     }} 
    ] 
) 
1

आप क्लाइंट पक्ष जावास्क्रिप्ट का उपयोग करने के लिए खुले हैं, तो आप प्रत्यावर्तन मोंगो खोल पर इस लक्ष्य को हासिल करने के लिए उपयोग कर सकते हैं:

var pushAncesstors = function (name, doc) { 
    if(doc.parent) { 
    db.collection.update({name : name}, {$addToSet : {"ancesstors" : {name : doc.parent}}}); 
    pushAncesstors(name, db.collection.findOne({name : doc.parent})) 
    } 
} 

db.collection.find().forEach(function (doc){ 
    pushAncesstors(doc.name, doc); 
}) 

यह आपको सभी उत्पादों के लिए पूरा hirearchy दे देंगे। नमूना उत्पादन:

{ "_id" : "1", "name" : "A", "parent" : "" } 
{ "_id" : "2", "name" : "B", "parent" : "A", "ancesstors" : [ { "name" : "A" } ] } 
{ "_id" : "3", "name" : "C", "parent" : "B", "ancesstors" : [ { "name" : "B" }, { "name" : "A" } ] } 
{ "_id" : "4", "name" : "D", "parent" : "C", "ancesstors" : [ { "name" : "C" }, { "name" : "B" }, { "name" : "A" } ] } 

आपकी आवश्यकता सही संग्रह अद्यतन करते हैं, एक diffferent संग्रह में डेटा डालें और वहाँ अद्यतन करने के लिए नहीं है। pushAncesstors फ़ंक्शन में बदल जाएगा:

var pushAncesstors = function (name, doc) { 
    if(doc.parent) { 
    db.outputColl.save(doc) 
    db.outputColl.update({name : name}, {$addToSet : {"ancesstors" : {name : doc.parent}}}); 
    pushAncesstors(name, db.collection.findOne({name : doc.parent})) 
    } 
} 
+0

उत्तर के लिए धन्यवाद। हां, मैं क्लाइंट साइड जावास्क्रिप्ट का उपयोग करने के लिए खुला हूं। लेकिन, उपरोक्त एक मौजूदा दस्तावेज़ को अपडेट करेगा, है ना? पदानुक्रम प्राप्त करने की आवश्यकता है लेकिन दस्तावेज़ को अपडेट नहीं करना है। – RaR

+0

वर्तमान संग्रह को अनमोडिफाइड छोड़ने के लिए उत्तर अपडेट किया गया। – ares