2012-10-20 12 views
5

मैं इस तरह एक साधारण db लेआउट:MongoDB एकत्रीकरण के साथ गिनती और औसत की गणना कर रहा

client 
    id 
    sex (male/female) 
    birthday (date)  

client 
    id 
    sex (male/female) 
    birthday (date) 

(...) 

मैं एक एकत्रीकरण आदेश आउटपुट कि कितने पुरुष और महिला ग्राहकों मुझे मिल गया है लिखने के लिए कोशिश कर रहा हूँ, और मैं 'पुरुषों और महिलाओं की औसत आयु को भी आउटपुट करना पसंद है, मुझे यकीन नहीं है कि मैं इसे एक ही कमांड में कर सकता हूं या मुझे 2 अलग-अलग लोगों की आवश्यकता है?

// Count of males/females, average age 
Clients.aggregate({ 
    $project : {"sex"  : 1, 
      "sexCount" : 1, 
      "birthday" : 1, 
      "avgAge" : 1 
       } 
    }, 
    { 
     $match: {"sex": {$exists: true}} 
    }, 
    { 
     $group: { 
        _id  : "$sex", 
      sexCount : { $sum: 1 }, 
      avgAge : { $avg: "$birthday" }, 
      } 
    }, 
    { $sort: { _id: 1 } } 
    , function(err, sex_dbres) { 
      if (err) 
       throw err; 
      else{ 
       (...) 
      } 
     });   

ऊपर दिए गए कोड के साथ मुझे नर/मादा की संख्या मिलती है, लेकिन avgAge 0. के रूप में आता है। कोई विचार?

बहुत धन्यवाद

+0

ध्यान दें कि आपको फ़ील्ड्स सेक्स को प्रोजेक्ट करने की आवश्यकता नहीं है या पहले चरण में avgAge के रूप में उन फ़ील्ड हैं जिन्हें आप $ समूह चरण में गणना करेंगे। –

उत्तर

4

तारीख वस्तु नहीं हो सकता "औसतन", लेकिन संख्या कर सकते हैं। आप अपनी तिथियों को टाइमस्टैम्प मान में बदल सकते हैं, और उसके बाद औसत पा सकते हैं। लेकिन फिर भी यह औसत आयु नहीं होगी, आपको एकत्रीकरण समारोह के बाहर वर्तमान तारीख से परिणाम घटाना होगा।

एक और विकल्प यह मानना ​​है कि उम्र के केवल वर्ष के हिस्से का उपयोग करके गणना की जा सकती है (यानी, अगर मैं 1 दिसंबर, 2000 को पैदा हुआ था, तो आज की रिपोर्ट में मैं 12 वर्ष का हूं, 11 नहीं)। इस मामले में आप वर्ष मूल्य निकालने के लिए date operators का उपयोग कर सकते हैं।

$project : {"sex"  : 1, 
      "sexCount" : 1, 
      "year" : {$year: "$birthday"}, 
      } 
}, 
$project : {"sex"  : 1, 
      "sexCount" : 1, 
      "age" : {$subtract: [2012, '$year']}, 
      } 
}, 
+0

धन्यवाद। बस एहसास हुआ कि जन्मदिन स्ट्रिंग के रूप में संग्रहीत किया जाता है ("शनि मई 22 1982 00:00:00 जीएमटी + 0200") जो चीजों को थोड़ा और कठिन बनाता है। क्या इसे एक संख्या के रूप में डालना संभव है? मैंने केवल साल के हिस्से को पाने के लिए एक सबस्ट्रेट करने का प्रयास किया है, लेकिन फिर मुझे इसे एक संख्या में बदलने में परेशानी हो रही है, फिर आप प्रस्तावित $ घटाएं। यदि यह मुश्किल है तो मुझे लगता है कि मैं फ़ील्ड को एक तारीख में बदल सकता हूं। –

+0

रूपांतरण एकत्रीकरण ढांचे का हिस्सा नहीं है, मुझे लगता है कि आपको या तो MapReduce का उपयोग करने की आवश्यकता होगी जहां आप मनमाना जावास्क्रिप्ट कोड लिख सकते हैं, या अपने डेटाबेस के माध्यम से चला सकते हैं और सभी तिथियों को परिवर्तित कर सकते हैं। – Dmitry

+0

धन्यवाद! मैंने वर्ष को एक अलग क्षेत्र में निकाला और अब आसानी से औसत कर सकता है। –

6

जवाब बहुत सरल हो सकता है अगर आप मूल दस्तावेज़ में उम्र भंडारण कर रहे थे (के रूप में दिमित्री पोस्ट, तो आप सिर्फ एक सीधे avgAge:{$avg:"$age"} अपने $group कदम में कर सकता है।

एकत्रीकरण फ्रेमवर्क हालांकि सुंदर गंधा है और कई शांत ऑपरेटरों जिसे आप "मक्खी पर" इस ​​लापता उम्र क्षेत्र की गणना करने की अनुमति मिलती है

मैं तो यह आसान है क्या हो रहा है देखने के लिए एकत्रीकरण के हर कदम एक चर में संग्रहीत करने के लिए जा रहा हूँ:।

> db.client.find({},{_id:0}) 
{ "sex" : "male", "bday" : ISODate("2000-02-02T08:00:00Z") } 
{ "sex" : "male", "bday" : ISODate("1987-02-02T08:00:00Z") } 
{ "sex" : "female", "bday" : ISODate("1989-02-02T08:00:00Z") } 
{ "sex" : "female", "bday" : ISODate("1993-11-02T08:00:00Z") } 
> db.client.aggregate([ project1, project2, group, project3 ]) 
{ 
    "result" : [ 
     { 
      "sex" : "female", 
      "total" : 2, 
      "averageAge" : 21.34109589041096 
     }, 
     { 
      "sex" : "male", 
      "total" : 2, 
      "averageAge" : 19.215068493150685 
     } 
    ], 
    "ok" : 1 
} 
> 

कारण इस सरल नहीं है वर्तमान में एकत्रीकरण फ्रेमवर्क तारीखों के प्रत्यक्ष घटाव का समर्थन नहीं करता है:

today = new Date(); 
// split today and bday into numerical year and numerical day-of-the-year 
project1= { 
    "$project" : { 
     "sex" : 1, 
     "todayYear" : { 
      "$year" : today 
     }, 
     "todayDay" : { 
      "$dayOfYear" : today 
     }, 
     "by" : { 
      "$year" : "$bday" 
     }, 
     "bd" : { 
      "$dayOfYear" : "$bday" 
     } 
    } 
}; 
// calculate age in days by subtracting bday in days from today in days 
project2 = { 
    "$project" : { 
     "sex" : 1, 
     "age" : { 
      "$subtract" : [ 
       { 
        "$add" : [ 
         { 
          "$multiply" : [ 
           "$todayYear", 
           365 
          ] 
         }, 
         "$todayDay" 
        ] 
       }, 
       { 
        "$add" : [ 
         { 
          "$multiply" : [ 
           "$by", 
           365 
          ] 
         }, 
         "$bd" 
        ] 
       } 
      ] 
     } 
    } 
}; 
// sum up for each sex the count and compute avg age (in days) 
group = { 
    "$group" : { 
     "_id" : "$sex", 
     "total" : { 
      "$sum" : 1 
     }, 
     "avgAge" : { 
      "$avg" : "$age" 
     } 
    } 
}; 
// divide days by 365 to get age in years. 
project3 = { 
    "$project" : { 
     "_id" : 0, 
     "sex" : "$_id", 
     "total" : 1, 
     "averageAge" : { 
      "$divide" : [ 
       "$avgAge", 
       365 
      ] 
     } 
    } 
}; 

अब आप एकत्रीकरण चला सकते हैं। कृपया https://jira.mongodb.org/browse/SERVER-6239 के लिए वोट दें जो अगली बड़ी रिलीज के लिए लक्षित है - एक बार इसे कार्यान्वित करने के बाद इसे सीधे तारीखों के घटाव की अनुमति देनी चाहिए (हालांकि आपको अभी भी उचित ग्रैन्युलरिटी में बदलने की आवश्यकता होगी, इस मामले में वर्षों में शायद)।

+0

निश्चित रूप से ऐसा करने का एक और तरीका बडे को दिन में परिवर्तित करना, समूह चरण में उन लोगों का औसत प्राप्त करना और अंतिम परियोजना गणना युग में आज से दिन में कम से कम दिन में 365 से विभाजित हो सकता है। –

+0

धन्यवाद अस्या, इसी तरह के दृष्टिकोण ऊपरोक्त अनुसार। –

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