2016-05-07 11 views
5

यहाँ का उपयोग कर स्थिति मेरे संग्रह है:

collection1:

{ 
    user1: 1, 
    user2: 2, 
    percent: 0.56 
} 

collection2:

{ 
    user1: 1, 
    user2: 2, 
    percent: 0.3 
} 

मैं 'user1' और 'द्वारा दो संग्रह में शामिल होने के लिए चाहते हैं user2 '।

परिणाम इस तरह:

{ 
    user1: 1, 
    user2: 2, 
    percent1: 0.56, 
    percent2: 0.3 
} 

मैं पाइपलाइन कैसे लिख सकता हूँ?

+0

नहीं, आप 'user1' और 'user2' का उपयोग नहीं कर सकते हैं, यह संभव नहीं है क्योंकि 'स्थानीय फ़ील्ड' और 'विदेशी फ़ील्ड' दोनों केवल एक फ़ील्ड का नाम लेते हैं। – styvane

+0

मुझे यह करने का एक तरीका मिल गया है। एक नए संग्रह में संग्रह और इसे समूहित करें। – user6148078

उत्तर

20

हम संस्करण 3.6 और नए में $lookup एकत्रीकरण पाइपलाइन ऑपरेटर के साथ कई स्थितियों को जोड़ सकते हैं।

हमें let वैकल्पिक फ़ील्ड का उपयोग कर फ़ील्ड के मानों को चर में असाइन करने की आवश्यकता है; फिर आप उन चरों को pipeline फ़ील्ड चरणों में एक्सेस करते हैं जहां आप संग्रह पर चलाने के लिए पाइपलाइन निर्दिष्ट करते हैं।

ध्यान दें कि $match चरण में, हम फ़ील्ड के मान की तुलना करने के लिए $expr मूल्यांकन क्वेरी ऑपरेटर का उपयोग करते हैं।

पाइप लाइन में अंतिम चरण $replaceRoot एकत्रीकरण पाइपलाइन मंच है जहाँ हम बस $mergeObjects ऑपरेटर का उपयोग $$ROOT दस्तावेज़ के भाग के साथ $lookup मर्ज करने के परिणाम है।

db.collection2.aggregate([ 
     { 
      $lookup: { 
      from: "collection1", 
      let: { 
       firstUser: "$user1", 
       secondUser: "$user2" 
      }, 
      pipeline: [ 
       { 
        $match: { 
         $expr: { 
         $and: [ 
          { 
           $eq: [ 
            "$user1", 
            "$$firstUser" 
           ] 
          }, 
          { 
           $eq: [ 
            "$user2", 
            "$$secondUser" 
           ] 
          } 
         ] 
         } 
        } 
       } 
      ], 
      as: "result" 
      } 
     }, 
     { 
      $replaceRoot: { 
      newRoot: { 
       $mergeObjects:[ 
        { 
         $arrayElemAt: [ 
         "$result", 
         0 
         ] 
        }, 
        { 
         percent1: "$$ROOT.percent1" 
        } 
       ] 
      } 
      } 
     } 
    ] 
) 

इस पाइपलाइन की पैदावार कुछ है कि इस तरह दिखेगा:

{ 
    "_id" : ObjectId("59e1ad7d36f42d8960c06022"), 
    "user1" : 1, 
    "user2" : 2, 
    "percent" : 0.3, 
    "percent1" : 0.56 
} 

आप संस्करण 3.6+ पर नहीं हैं, तो आप पहली बार अपने क्षेत्र से एक का उपयोग शामिल हो सकते हैं कहते हैं कि "user1" तो चलो वहां से आप $unwind एकत्रीकरण पाइपलाइन ऑपरेटर का उपयोग कर मिलान दस्तावेज़ की सरणी को खोलें। पाइपलाइन में अगला चरण $redact चरण है जहां आप उन दस्तावेज़ों को फ़िल्टर करते हैं जहां "शामिल" संग्रह से "उपयोगकर्ता 2" का मान और इनपुट दस्तावेज़ $$KEEP और $$PRUNE सिस्टम चर का उपयोग करके बराबर नहीं है। फिर आप अपने दस्तावेज़ को $project चरण में दोबारा बदल सकते हैं।

db.collection1.aggregate([ 
    { "$lookup": { 
     "from": "collection2", 
     "localField": "user1", 
     "foreignField": "user1", 
     "as": "collection2_doc" 
    }}, 
    { "$unwind": "$collection2_doc" }, 
    { "$redact": { 
     "$cond": [ 
      { "$eq": [ "$user2", "$collection2_doc.user2" ] }, 
      "$$KEEP", 
      "$$PRUNE" 
     ] 
    }}, 
    { "$project": { 
     "user1": 1, 
     "user2": 1, 
     "percent1": "$percent", 
     "percent2": "$collection2_doc.percent" 
    }} 
]) 

पैदा करता है जो:

{ 
    "_id" : ObjectId("572daa87cc52a841bb292beb"), 
    "user1" : 1, 
    "user2" : 2, 
    "percent1" : 0.56, 
    "percent2" : 0.3 
} 

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

db.collection3.insertMany(
    db.collection1.find({}, {"_id": 0}) 
    .toArray() 
    .concat(db.collection2.find({}, {"_id": 0}).toArray()) 
) 
फिर

$group "user1" और "user2"

db.collection3.aggregate([ 
    { "$group": { 
     "_id": { "user1": "$user1", "user2": "$user2" }, 
     "percent": { "$push": "$percent" } 
    }} 
]) 

जो पैदावार करके अपने दस्तावेज़ों:

{ "_id" : { "user1" : 1, "user2" : 2 }, "percent" : [ 0.56, 0.3 ] } 
+1

यह काम करता है लेकिन यह बहुत धीमा है। – user6148078

+0

@ user6148078 '$ unwind' मंच शायद यहां अपराधी है। यह भी ध्यान दें कि '$ redact' संग्रह स्कैन करता है। लेकिन यदि यह संभव नहीं है तो एक विलय करें, मुझे लगता है कि यह सबसे अच्छा है जो आप प्राप्त कर सकते हैं। – styvane

+0

इस पर ध्यान देने से मुझे मोंगो से अधिक SQL तरीके की सराहना होती है। – user2223059

1

आप एकाधिक क्षेत्र कर सकते हैं $ मैच और $ का उपयोग कर से मेल खाता है परियोजना पाइपलाइन। (विस्तृत जवाब यहाँ देख - mongoDB Join on multiple fields)

db.collection1.aggregate([ 
        {"$lookup": { 
        "from": "collection2", 
        "localField": "user1", 
        "foreignField": "user1", 
        "as": "c2" 
        }}, 
        {"$unwind": "$c2"}, 

        {"$project": { 
        "user2Eq": {"$eq": ["$user2", "$c2.user2"]}, 
        "user1": 1, "user2": 1, 
        "percent1": "$percent", "percent2": "$c2.percent" 
        }}, 

        {"$match": { 
        {"user2Eq": {"$eq": True}} 
        }}, 

        {"$project": { 
        "user2Eq": 0 
        }} 

        ]) 
0

आप अपने डेटा मॉडल करने के लिए प्रयास कर रहे हैं, और यहाँ आया करता है, तो MongoDB प्रदर्शन कर सकते हैं ऐसा करने के लिए निर्णय लेने से पहले कई क्षेत्रों पर मिलती है, तो कृपया पर पढ़ें जाँच करने के लिए।

जबकि मोंगोडीबी शामिल हो सकता है, तो आपके पास अपने एप्लिकेशन एक्सेस पैटर्न के अनुसार डेटा मॉडल करने की स्वतंत्रता भी है।

{ 
    user1: 1, 
    user2: 2, 
    percent1: 0.56, 
    percent2: 0.3 
} 

अब आप इस संग्रह पर सभी कार्यों आप में शामिल होने के द्वारा किया जाता है | प्रदर्शन कर सकते हैं: के रूप में प्रश्न में प्रस्तुत आंकड़ों के रूप में सरल है, तो हम बस एक संग्रह है कि इस तरह दिखता है बनाए रख सकते हैं। हम शामिल होने से बचने की कोशिश क्यों कर रहे हैं? क्योंकि वे sharded संग्रह (docs) द्वारा समर्थित नहीं हैं, जो आपको आवश्यकता होने पर स्केलिंग से रोक देगा। डेटा को सामान्यीकृत करना (अलग-अलग तालिकाओं/संग्रह होने) एसक्यूएल में बहुत अच्छी तरह से काम करता है, लेकिन जब मोंगो की बात आती है, तो जुड़ने से बचने से ज्यादातर मामलों में बिना किसी परिणाम के फायदे मिल सकते हैं। मोंगो डीबी में केवल सामान्यीकरण का उपयोग करें जब आपके पास कोई अन्य विकल्प न हो। docs से:

सामान्य तौर पर, सामान्यीकृत डेटा मॉडल का उपयोग करें:

  • जब से डेटा का डुप्लिकेट में परिणाम होगा embedding लेकिन पर्याप्त पढ़ने प्रदर्शन फायदे दोहराव के निहितार्थ पल्ला झुकना करने के लिए नहीं प्रदान कर पाएँगे।
  • अधिक जटिल कई से अधिक रिश्तों का प्रतिनिधित्व करने के लिए। बड़े पदानुक्रमित डेटा सेट मॉडल के लिए

चेक here embedding और कारण है कि आप सामान्य से अधिक यह चुनते हैं के बारे में अधिक पढ़ने के लिए।

संबंधित मुद्दे