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

प्रारंभ और समाप्ति सीमा पर समूह और गणना करें

इसके लिए एल्गोरिदम मूल रूप से दो मानों के अंतराल के बीच मूल्यों को "पुनरावृत्ति" करना है। MongoDB के पास इससे निपटने के कुछ तरीके हैं, जो हमेशा mapReduce() और aggregate()<के लिए उपलब्ध नई सुविधाओं के साथ /कोड> विधि।

मैं आपके चयन का विस्तार जानबूझकर एक अतिव्यापी माह दिखाने के लिए कर रहा हूं क्योंकि आपके उदाहरणों में एक नहीं था। इसके परिणामस्वरूप "HGV" मान आउटपुट के "तीन" महीनों में दिखाई देंगे।

{
        "_id" : 1,
        "startDate" : ISODate("2017-01-01T00:00:00Z"),
        "endDate" : ISODate("2017-02-25T00:00:00Z"),
        "type" : "CAR"
}
{
        "_id" : 2,
        "startDate" : ISODate("2017-02-17T00:00:00Z"),
        "endDate" : ISODate("2017-03-22T00:00:00Z"),
        "type" : "HGV"
}
{
        "_id" : 3,
        "startDate" : ISODate("2017-02-17T00:00:00Z"),
        "endDate" : ISODate("2017-04-22T00:00:00Z"),
        "type" : "HGV"
}

कुल - MongoDB 3.4 की आवश्यकता है

db.cars.aggregate([
  { "$addFields": {
    "range": {
      "$reduce": {
        "input": { "$map": {
          "input": { "$range": [ 
            { "$trunc": { 
              "$divide": [ 
                { "$subtract": [ "$startDate", new Date(0) ] },
                1000
              ]
            }},
            { "$trunc": {
              "$divide": [
                { "$subtract": [ "$endDate", new Date(0) ] },
                1000
              ]
            }},
            60 * 60 * 24
          ]},
          "as": "el",
          "in": {
            "$let": {
              "vars": {
                "date": {
                  "$add": [ 
                    { "$multiply": [ "$$el", 1000 ] },
                    new Date(0)
                  ]
                },
                "month": {
                }
              },
              "in": {
                "$add": [
                  { "$multiply": [ { "$year": "$$date" }, 100 ] },
                  { "$month": "$$date" }
                ]
              }
            }
          }
        }},
        "initialValue": [],
        "in": {
          "$cond": {
            "if": { "$in": [ "$$this", "$$value" ] },
            "then": "$$value",
            "else": { "$concatArrays": [ "$$value", ["$$this"] ] }
          }
        }
      }
    }
  }},
  { "$unwind": "$range" },
  { "$group": {
    "_id": {
      "type": "$type",
      "month": "$range"
    },
    "count": { "$sum": 1 }
  }},
  { "$sort": { "_id": 1 } },
  { "$group": {
    "_id": "$_id.type",
    "monthCounts": { 
      "$push": { "month": "$_id.month", "count": "$count" }
    }
  }}
])

यह काम करने की कुंजी है $range ऑपरेटर जो लागू करने के लिए "प्रारंभ" और "अंत" के साथ-साथ "अंतराल" के लिए मान लेता है। परिणाम "प्रारंभ" से लिए गए मानों की एक सरणी है और "अंत" तक पहुंचने तक वृद्धि हुई है।

हम इसका उपयोग startDate . के साथ करते हैं और समाप्ति तिथि उन मानों के बीच संभावित तिथियां उत्पन्न करने के लिए। आप देखेंगे कि $range . के बाद से हमें यहां कुछ गणित करने की आवश्यकता है केवल 32-बिट पूर्णांक लेता है, लेकिन हम मिलीसेकंड को टाइमस्टैम्प मानों से दूर ले जा सकते हैं ताकि यह ठीक रहे।

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

इसलिए पहले एकत्रीकरण पाइपलाइन चरण का परिणाम दस्तावेज़ में एक नया क्षेत्र है जो startDate के बीच कवर किए गए सभी विशिष्ट महीनों का "सरणी" है। और समाप्ति तिथि . यह बाकी ऑपरेशन के लिए "इटरेटर" देता है।

"इटरेटर" से मेरा मतलब उस समय से है जब हम $unwind<लागू करते हैं /कोड> हमें अंतराल में शामिल प्रत्येक विशिष्ट महीने के लिए मूल दस्तावेज़ की एक प्रति प्राप्त होती है। इसके बाद निम्नलिखित दो $group को अनुमति देता है $योग , और अगला $group कुंजी को केवल "टाइप" बनाता है और परिणामों को के माध्यम से एक सरणी में रखता है। $पुश

यह उपरोक्त डेटा पर परिणाम देता है:

{
        "_id" : "HGV",
        "monthCounts" : [
                {
                        "month" : 201702,
                        "count" : 2
                },
                {
                        "month" : 201703,
                        "count" : 2
                },
                {
                        "month" : 201704,
                        "count" : 1
                }
        ]
}
{
        "_id" : "CAR",
        "monthCounts" : [
                {
                        "month" : 201701,
                        "count" : 1
                },
                {
                        "month" : 201702,
                        "count" : 1
                }
        ]
}

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

यदि आपका दिल वास्तव में शून्य मानों पर सेट है, तो आपको $मिनट और $max मान, और इन्हें प्रत्येक आपूर्ति किए गए संभावित श्रेणी मान के लिए प्रतियां उत्पन्न करने के लिए पाइपलाइन को "बलपूर्वक" करने के लिए पास करें।

तो इस बार "रेंज" को सभी दस्तावेज़ों के लिए बाहरी रूप से बनाया गया है, और फिर आप $cond संचायक में यह देखने के लिए कि क्या वर्तमान डेटा उत्पादित समूहीकृत सीमा के भीतर है। इसके अलावा चूंकि पीढ़ी "बाहरी" है, हमें वास्तव में $range के MongoDB 3.4 ऑपरेटर की आवश्यकता नहीं है , इसलिए इसे पुराने संस्करणों पर भी लागू किया जा सकता है:

// Get min and max separately 
var ranges = db.cars.aggregate(
 { "$group": {
   "_id": null,
   "startRange": { "$min": "$startDate" },
   "endRange": { "$max": "$endDate" }
 }}
).toArray()[0]

// Make the range array externally from all possible values
var range = [];
for ( var d = new Date(ranges.startRange.valueOf()); d <= ranges.endRange; d.setUTCMonth(d.getUTCMonth()+1)) {
  var v = ( d.getUTCFullYear() * 100 ) + d.getUTCMonth()+1;
  range.push(v);
}

// Run conditional aggregation
db.cars.aggregate([
  { "$addFields": { "range": range } },
  { "$unwind": "$range" },
  { "$group": {
    "_id": {
      "type": "$type",
      "month": "$range"
    },
    "count": { 
      "$sum": {
        "$cond": {
          "if": {
            "$and": [
              { "$gte": [
                "$range",
                { "$add": [
                  { "$multiply": [ { "$year": "$startDate" }, 100 ] },
                  { "$month": "$startDate" }
                ]}
              ]},
              { "$lte": [
                "$range",
                { "$add": [
                  { "$multiply": [ { "$year": "$endDate" }, 100 ] },
                  { "$month": "$endDate" }
                ]}
              ]}
            ]
          },
          "then": 1,
          "else": 0
        }
      }
    }
  }},
  { "$sort": { "_id": 1 } },
  { "$group": {
    "_id": "$_id.type",
    "monthCounts": { 
      "$push": { "month": "$_id.month", "count": "$count" }
    }
  }}
])

जो सभी समूहों पर सभी संभावित महीनों के लिए लगातार शून्य भरता उत्पन्न करता है:

{
        "_id" : "HGV",
        "monthCounts" : [
                {
                        "month" : 201701,
                        "count" : 0
                },
                {
                        "month" : 201702,
                        "count" : 2
                },
                {
                        "month" : 201703,
                        "count" : 2
                },
                {
                        "month" : 201704,
                        "count" : 1
                }
        ]
}
{
        "_id" : "CAR",
        "monthCounts" : [
                {
                        "month" : 201701,
                        "count" : 1
                },
                {
                        "month" : 201702,
                        "count" : 1
                },
                {
                        "month" : 201703,
                        "count" : 0
                },
                {
                        "month" : 201704,
                        "count" : 0
                }
        ]
}

MapReduce

MongoDB के सभी संस्करण mapReduce का समर्थन करते हैं, और जैसा कि ऊपर बताया गया है, "इटरेटर" का साधारण मामला के लिए द्वारा नियंत्रित किया जाता है मैपर में लूप। हम पहले $group . तक जेनरेट किए गए आउटपुट को प्राप्त कर सकते हैं ऊपर से केवल ऐसा करके:

db.cars.mapReduce(
  function () {
    for ( var d = this.startDate; d <= this.endDate;
      d.setUTCMonth(d.getUTCMonth()+1) )
    { 
      var m = new Date(0);
      m.setUTCFullYear(d.getUTCFullYear());
      m.setUTCMonth(d.getUTCMonth());
      emit({ id: this.type, date: m},1);
    }
  },
  function(key,values) {
    return Array.sum(values);
  },
  { "out": { "inline": 1 } }
)

जो उत्पादन करता है:

{
        "_id" : {
                "id" : "CAR",
                "date" : ISODate("2017-01-01T00:00:00Z")
        },
        "value" : 1
},
{
        "_id" : {
                "id" : "CAR",
                "date" : ISODate("2017-02-01T00:00:00Z")
        },
        "value" : 1
},
{
        "_id" : {
                "id" : "HGV",
                "date" : ISODate("2017-02-01T00:00:00Z")
        },
        "value" : 2
},
{
        "_id" : {
                "id" : "HGV",
                "date" : ISODate("2017-03-01T00:00:00Z")
        },
        "value" : 2
},
{
        "_id" : {
                "id" : "HGV",
                "date" : ISODate("2017-04-01T00:00:00Z")
        },
        "value" : 1
}

इसलिए इसमें सरणियों के लिए कंपाउंड करने के लिए दूसरा समूह नहीं है, लेकिन हमने समान मूल समेकित आउटपुट का उत्पादन किया।




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. MongoDB में पहले सरणी मान को किसी अन्य फ़ील्ड में कॉपी करें

  2. त्रैमासिक वार ग्रुप डेट कैसे करें?

  3. जहां सी # का उपयोग कर MongoDB संग्रह में एक एम्बेडेड दस्तावेज़ के खंड क्वेरी में प्रोजेक्शन

  4. नोड.जेएस से मोंगोडब से कनेक्ट करते समय ECONNREFUSED त्रुटि

  5. मोंगोडब में संग्रहीत फ़ंक्शन को कॉल करें

© कॉपीराइट http://hi.sqldat.com सर्वाधिकार सुरक्षित