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

कुल का उपयोग कर चल रहे कुल की गणना कैसे करें?

कम से कम प्रारंभिक समस्या समाधान में, एकत्रीकरण ढांचे की तुलना में मानचित्र के लिए वास्तव में अधिक उपयुक्त है। एकत्रीकरण ढांचे में पिछले दस्तावेज़ के मूल्य, या दस्तावेज़ के पिछले "समूहीकृत" मूल्य की कोई अवधारणा नहीं है, इसलिए यह ऐसा नहीं कर सकता है।

दूसरी ओर, mapReduce में एक "वैश्विक दायरा" होता है जिसे संसाधित होने पर चरणों और दस्तावेज़ों के बीच साझा किया जा सकता है। यह आपको आवश्यक दिन के अंत में वर्तमान शेष राशि के लिए "रनिंग टोटल" प्राप्त करेगा।

db.collection.mapReduce(
  function () {
    var date = new Date(this.dateEntry.valueOf() -
      ( this.dateEntry.valueOf() % ( 1000 * 60 * 60 * 24 ) )
    );

    emit( date, this.amount );
  },
  function(key,values) {
      return Array.sum( values );
  },
  { 
      "scope": { "total": 0 },
      "finalize": function(key,value) {
          total += value;
          return total;
      },
      "out": { "inline": 1 }
  }
)      

यह तिथि समूह के आधार पर योग होगा और फिर "अंतिम रूप" खंड में यह प्रत्येक दिन से एक संचयी योग बनाता है।

   "results" : [
            {
                    "_id" : ISODate("2015-01-06T00:00:00Z"),
                    "value" : 50
            },
            {
                    "_id" : ISODate("2015-01-07T00:00:00Z"),
                    "value" : 150
            },
            {
                    "_id" : ISODate("2015-01-09T00:00:00Z"),
                    "value" : 179
            }
    ],

लंबी अवधि में आपके लिए बेहतर होगा कि आप प्रत्येक दिन के लिए एक प्रविष्टि के साथ एक अलग संग्रह रखें और $inc का उपयोग करके शेष राशि में बदलाव करें। एक अद्यतन में। बस एक $inc भी करें पिछले दिन की शेष राशि को आगे ले जाने वाला एक नया दस्तावेज़ बनाने के लिए प्रत्येक दिन की शुरुआत में अपरर्ट करें:

// increase balance
db.daily(
    { "dateEntry": currentDate },
    { "$inc": { "balance": amount } },
    { "upsert": true }
);

// decrease balance
db.daily(
    { "dateEntry": currentDate },
    { "$inc": { "balance": -amount } },
    { "upsert": true }
);

// Each day
var lastDay = db.daily.findOne({ "dateEntry": lastDate });
db.daily(
    { "dateEntry": currentDate },
    { "$inc": { "balance": lastDay.balance } },
    { "upsert": true }
);

ऐसा कैसे नहीं करें

हालांकि यह सच है कि मूल लेखन के बाद से अधिक ऑपरेटरों को एकत्रीकरण ढांचे में पेश किया गया है, यहां जो पूछा जा रहा है वह अभी भी व्यावहारिक नहीं है एग्रीगेशन स्टेटमेंट में करना है।

वही मूल नियम लागू होता है जो एकत्रीकरण ढांचा नहीं कर सकता पिछले "दस्तावेज़" से एक मान का संदर्भ लें, न ही यह "वैश्विक चर" को स्टोर कर सकता है। "हैकिंग" यह सभी परिणामों के बल द्वारा एक सरणी में:

db.collection.aggregate([
  { "$group": {
    "_id": { 
      "y": { "$year": "$dateEntry" }, 
      "m": { "$month": "$dateEntry" }, 
      "d": { "$dayOfMonth": "$dateEntry" } 
    }, 
    "amount": { "$sum": "$amount" }
  }},
  { "$sort": { "_id": 1 } },
  { "$group": {
    "_id": null,
    "docs": { "$push": "$$ROOT" }
  }},
  { "$addFields": {
    "docs": {
      "$map": {
        "input": { "$range": [ 0, { "$size": "$docs" } ] },
        "in": {
          "$mergeObjects": [
            { "$arrayElemAt": [ "$docs", "$$this" ] },
            { "amount": { 
              "$sum": { 
                "$slice": [ "$docs.amount", 0, { "$add": [ "$$this", 1 ] } ]
              }
            }}
          ]
        }
      }
    }
  }},
  { "$unwind": "$docs" },
  { "$replaceRoot": { "newRoot": "$docs" } }
])

यह न तो एक निष्पादक समाधान है और न ही "सुरक्षित" यह देखते हुए कि बड़े परिणाम सेट 16 एमबी बीएसओएन सीमा के उल्लंघन की वास्तविक संभावना को चलाते हैं। "सुनहरा नियम" . के रूप में , कुछ भी जो सभी सामग्री को एक दस्तावेज़ की सरणी में रखने का प्रस्ताव करता है:

{ "$group": {
  "_id": null,
  "docs": { "$push": "$$ROOT" }
}}

तो यह एक बुनियादी दोष है और इसलिए समाधान नहीं

निष्कर्ष

इसे संभालने के अधिक निर्णायक तरीके आम तौर पर परिणामों के चल रहे कर्सर पर पोस्ट प्रोसेसिंग होंगे:

var globalAmount = 0;

db.collection.aggregate([
  { $group: {
    "_id": { 
      y: { $year:"$dateEntry"}, 
      m: { $month:"$dateEntry"}, 
      d: { $dayOfMonth:"$dateEntry"} 
    }, 
    amount: { "$sum": "$amount" }
  }},
  { "$sort": { "_id": 1 } }
]).map(doc => {
  globalAmount += doc.amount;
  return Object.assign(doc, { amount: globalAmount });
})

तो सामान्य तौर पर यह हमेशा बेहतर होता है:

  • कुल योग के लिए कर्सर पुनरावृत्ति और ट्रैकिंग चर का उपयोग करें। mapReduce नमूना उपरोक्त सरलीकृत प्रक्रिया का एक काल्पनिक उदाहरण है।

  • पूर्व-एकत्रित योग का उपयोग करें। संभवत:आपकी पूर्व-एकत्रीकरण प्रक्रिया के आधार पर कर्सर पुनरावृत्ति के साथ मिलकर, चाहे वह केवल अंतराल योग हो या "कैरीड फ़ॉरवर्ड" रनिंग टोटल।

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

डेटाबेस को उन चीजों को करने दें जिनमें वे अच्छे हैं, क्योंकि आप "हेरफेर" को इसके बजाय कोड में बेहतर तरीके से नियंत्रित करते हैं।



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. MongoDB - एकत्रीकरण - सरणी में अद्वितीय आइटम प्राप्त करने के लिए

  2. नेवला findOneAndUpdate से लौटने के लिए फ़ील्ड का चयन करें

  3. दस्तावेज़ में Mongoengine निर्माण_समय विशेषता

  4. MongoDB छँटाई

  5. लेखन त्रुटि:ObjectId('') JSON क्रमानुसार नहीं है