MongoDB
 sql >> डेटाबेस >  >> NoSQL >> MongoDB

एक प्रश्न में प्रत्येक संपत्ति के लिए अलग-अलग मूल्यों और गणनाओं को समूहित करें

उपलब्ध संस्करण के आधार पर अलग-अलग दृष्टिकोण हैं, लेकिन वे सभी अनिवार्य रूप से आपके दस्तावेज़ फ़ील्ड को "सरणी" में अलग-अलग दस्तावेज़ों में बदलने के लिए टूट जाते हैं, फिर उस सरणी को $unwind और लगातार $group कर रहे हैं आउटपुट योग और सरणियों को संचित करने के लिए चरण।

MongoDB 3.4.4 और इसके बाद के संस्करण

नवीनतम रिलीज़ में विशेष ऑपरेटर होते हैं जैसे $arrayToObject और $objectToArray जो स्रोत दस्तावेज़ से प्रारंभिक "सरणी" में स्थानांतरण को पहले के रिलीज़ की तुलना में अधिक गतिशील बना सकता है:

db.profile.aggregate([
  { "$project": { 
     "_id": 0,
     "data": { 
       "$filter": {
         "input": { "$objectToArray": "$$ROOT" },
         "cond": { "$in": [ "$$this.k", ["gender","caste","education"] ] }
       }   
     }
  }},
  { "$unwind": "$data" },
  { "$group": {
    "_id": "$data",
    "total": { "$sum": 1 }  
  }},
  { "$group": {
    "_id": "$_id.k",
    "v": {
      "$push": { "name": "$_id.v", "total": "$total" } 
    }  
  }},
  { "$group": {
    "_id": null,
    "data": { "$push": { "k": "$_id", "v": "$v" } }
  }},
  { "$replaceRoot": {
    "newRoot": {
      "$arrayToObject": "$data"
    }
  }}
])

तो $objectToArray का इस्तेमाल करके आप प्रारंभिक दस्तावेज़ को इसकी कुंजियों और मानों की एक सरणी में "k" . के रूप में बनाते हैं और "v" वस्तुओं के परिणामी सरणी में कुंजियाँ। हम $filter लागू करते हैं यहाँ "कुंजी" द्वारा चयन करने के लिए। यहां $in का इस्तेमाल करके चाबियों की एक सूची के साथ हम चाहते हैं, लेकिन यह अधिक गतिशील रूप से चाबियों की सूची के रूप में "बहिष्कृत" करने के लिए उपयोग किया जा सकता है जहां वह छोटा था। यह स्थिति का मूल्यांकन करने के लिए केवल तार्किक ऑपरेटरों का उपयोग कर रहा है।

यहां अंतिम चरण में $replaceRoot का इस्तेमाल किया गया है और चूंकि हमारे सभी हेरफेर और बीच में "ग्रुपिंग" अभी भी उस "k" . को बनाए रखता है और "v" फ़ॉर्म में, हम तब $arrayToObject का उपयोग करते हैं आउटपुट में शीर्ष स्तर के दस्तावेज़ की "कुंजी" के परिणामस्वरूप हमारे "ऑब्जेक्ट्स की सरणी" को बढ़ावा देने के लिए यहां।

MongoDB 3.6 $mergeObjects

यहाँ एक अतिरिक्त शिकन के रूप में, MongoDB 3.6 में $मर्जऑब्जेक्ट्स जिसका उपयोग "accumulator के रूप में किया जा सकता है " एक $group में पाइपलाइन चरण भी, इस प्रकार $push और अंतिम $replaceRoot बनाना बस "डेटा" . को स्थानांतरित करना इसके बजाय लौटाए गए दस्तावेज़ के "रूट" की कुंजी:

db.profile.aggregate([
  { "$project": { 
     "_id": 0,
     "data": { 
       "$filter": {
         "input": { "$objectToArray": "$$ROOT" },
         "cond": { "$in": [ "$$this.k", ["gender","caste","education"] ] }
       }   
     }
  }},
  { "$unwind": "$data" },
  { "$group": { "_id": "$data", "total": { "$sum": 1 } }},
  { "$group": {
    "_id": "$_id.k",
    "v": {
      "$push": { "name": "$_id.v", "total": "$total" } 
    }  
  }},
  { "$group": {
    "_id": null,
    "data": {
      "$mergeObjects": {
        "$arrayToObject": [
          [{ "k": "$_id", "v": "$v" }]
        ] 
      }
    }  
  }},
  { "$replaceRoot": { "newRoot": "$data"  } }
])

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

ध्यान दें कि $arrayToObject "मूल्य" को वापस "कुंजी" के नाम में बदलने के लिए अभी भी आवश्यक है, लेकिन हम इसे समूहीकरण के बजाय संचय के दौरान करते हैं, क्योंकि नया संचय चाबियों के "विलय" की अनुमति देता है।

MongoDB 3.2

इसे एक संस्करण वापस लेना या यहां तक ​​​​कि यदि आपके पास एक मोंगोडीबी 3.4.x है जो 3.4.4 रिलीज से कम है, हम अभी भी इसका अधिकतर उपयोग कर सकते हैं लेकिन इसके बजाय हम सरणी के निर्माण को और अधिक स्थिर फैशन में भी सौदा करते हैं हमारे पास नहीं होने वाले एकत्रीकरण ऑपरेटरों के कारण आउटपुट पर अंतिम "ट्रांसफॉर्म" को अलग तरीके से संभालने के रूप में:

db.profile.aggregate([
  { "$project": {
    "data": [
      { "k": "gender", "v": "$gender" },
      { "k": "caste", "v": "$caste" },
      { "k": "education", "v": "$education" }
    ]
  }},
  { "$unwind": "$data" },
  { "$group": {
    "_id": "$data",
    "total": { "$sum": 1 }  
  }},
  { "$group": {
    "_id": "$_id.k",
    "v": {
      "$push": { "name": "$_id.v", "total": "$total" } 
    }  
  }},
  { "$group": {
    "_id": null,
    "data": { "$push": { "k": "$_id", "v": "$v" } }
  }},
  /*
  { "$replaceRoot": {
    "newRoot": {
      "$arrayToObject": "$data"
    }
  }}
  */
]).map( d => 
  d.data.map( e => ({ [e.k]: e.v }) )
    .reduce((acc,curr) => Object.assign(acc,curr),{})
)

यह बिल्कुल वैसी ही बात है, दस्तावेज़ के ऐरे में डायनेमिक ट्रांस्फ़ॉर्म होने के बजाय, हम वास्तव में प्रत्येक ऐरे सदस्य को एक ही "k" के साथ "स्पष्ट रूप से" असाइन करते हैं। और "v" अंकन। वास्तव में इस बिंदु पर केवल उन प्रमुख नामों को सम्मेलन के लिए रखते हुए क्योंकि यहां कोई भी एकत्रीकरण ऑपरेटर उस पर निर्भर नहीं है।

इसके अलावा $replaceRoot का उपयोग करने के बजाय , हम ठीक वैसा ही करते हैं जैसा कि पिछले पाइपलाइन चरण का कार्यान्वयन वहां कर रहा था, लेकिन इसके बजाय क्लाइंट कोड में। सभी MongoDB ड्राइवरों में cursor.map()<का कुछ कार्यान्वयन होता है। /कोड> "कर्सर ट्रांसफ़ॉर्म" को सक्षम करने के लिए। यहां शेल के साथ हम Array.map() और Array.reduce() उस आउटपुट को लेने के लिए और फिर से शीर्ष स्तर के दस्तावेज़ की कुंजी होने के लिए सरणी सामग्री को बढ़ावा देना।

MongoDB 2.6

और बीच में संस्करणों को कवर करने के लिए MongoDB 2.6 पर वापस आते हुए, केवल एक चीज जो यहां बदलती है वह है $map और एक $literal सरणी घोषणा के साथ इनपुट के लिए:

db.profile.aggregate([
  { "$project": {
    "data": {
      "$map": {
        "input": { "$literal": ["gender","caste", "education"] },
        "as": "k",
        "in": {
          "k": "$$k",
          "v": {
            "$cond": {
              "if": { "$eq": [ "$$k", "gender" ] },
              "then": "$gender",
              "else": {
                "$cond": {
                  "if": { "$eq": [ "$$k", "caste" ] },
                  "then": "$caste",
                  "else": "$education"
                }
              }    
            }
          }    
        }
      }
    }
  }},
  { "$unwind": "$data" },
  { "$group": {
    "_id": "$data",
    "total": { "$sum": 1 }  
  }},
  { "$group": {
    "_id": "$_id.k",
    "v": {
      "$push": { "name": "$_id.v", "total": "$total" } 
    }  
  }},
  { "$group": {
    "_id": null,
    "data": { "$push": { "k": "$_id", "v": "$v" } }
  }},
  /*
  { "$replaceRoot": {
    "newRoot": {
      "$arrayToObject": "$data"
    }
  }}
  */
])
.map( d => 
  d.data.map( e => ({ [e.k]: e.v }) )
    .reduce((acc,curr) => Object.assign(acc,curr),{})
)

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

3.4 के आधुनिक MongoDB में $switch है जो इस ब्रांचिंग को सरल बनाता है, फिर भी यह दर्शाता है कि तर्क हमेशा संभव था और $cond मोंगोडीबी 2.2 में एकत्रीकरण ढांचे को पेश किए जाने के बाद से ऑपरेटर आसपास रहा है।

फिर से, कर्सर परिणाम पर वही परिवर्तन लागू होता है क्योंकि वहां कुछ भी नया नहीं है और अधिकांश प्रोग्रामिंग भाषाओं में वर्षों तक ऐसा करने की क्षमता है, यदि स्थापना से नहीं।

बेशक मूल प्रक्रिया को MongoDB 2.2 पर भी वापस किया जा सकता है, लेकिन केवल सरणी निर्माण और $अनविंड भिन्न प्रकार से। लेकिन इस समय किसी को भी 2.8 से कम के किसी भी MongoDB को नहीं चलाना चाहिए, और 3.0 से भी आधिकारिक समर्थन तेजी से समाप्त हो रहा है।

आउटपुट

विज़ुअलाइज़ेशन के लिए, अंतिम "ट्रांसफ़ॉर्म" किए जाने से पहले सभी प्रदर्शित पाइपलाइनों के आउटपुट का निम्न रूप है:

/* 1 */
{
    "_id" : null,
    "data" : [ 
        {
            "k" : "gender",
            "v" : [ 
                {
                    "name" : "Male",
                    "total" : 3.0
                }, 
                {
                    "name" : "Female",
                    "total" : 2.0
                }
            ]
        }, 
        {
            "k" : "education",
            "v" : [ 
                {
                    "name" : "M.C.A",
                    "total" : 1.0
                }, 
                {
                    "name" : "B.E",
                    "total" : 3.0
                }, 
                {
                    "name" : "B.Com",
                    "total" : 1.0
                }
            ]
        }, 
        {
            "k" : "caste",
            "v" : [ 
                {
                    "name" : "Lingayath",
                    "total" : 3.0
                }, 
                {
                    "name" : "Vokkaliga",
                    "total" : 2.0
                }
            ]
        }
    ]
}

और फिर या तो $replaceRoot द्वारा या प्रदर्शित होने पर कर्सर रूपांतरित हो जाता है, परिणाम बन जाता है:

/* 1 */
{
    "gender" : [ 
        {
            "name" : "Male",
            "total" : 3.0
        }, 
        {
            "name" : "Female",
            "total" : 2.0
        }
    ],
    "education" : [ 
        {
            "name" : "M.C.A",
            "total" : 1.0
        }, 
        {
            "name" : "B.E",
            "total" : 3.0
        }, 
        {
            "name" : "B.Com",
            "total" : 1.0
        }
    ],
    "caste" : [ 
        {
            "name" : "Lingayath",
            "total" : 3.0
        }, 
        {
            "name" : "Vokkaliga",
            "total" : 2.0
        }
    ]
}

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




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. सी # ड्राइवर में मोंगोडीबी चेंज स्ट्रीम 'ऑपरेशन टाइप' कैसे सेट करें?

  2. pymongo:डुप्लिकेट हटाएं (मानचित्र कम करें?)

  3. Mongoose में एक और स्कीमा का संदर्भ देना

  4. birt . में सरणी सूची से समूह बनाना और डेटा का विश्लेषण करना

  5. $gte और <e mongo ऑपरेटर का उपयोग करें यदि दिनांक mongodb में स्ट्रिंग प्रारूप में है