使用MongoDB聚合计算计数和平均值

我有一个简单的数据库布局,像这样:

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

我试图写一个汇总命令,输出我有多less男女客户,我也想输出男性和女性的平均年龄,不知道我可以做同样的命令或我需要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.任何想法?

非常感谢

date对象不能被“平均”,但数字可以。 您可以将date转换为时间戳值,然后从中find平均值。 但仍然不是平均年龄,您需要从聚合函数以外的当前date中减去结果。

另一种select是假定年龄只能用date的一部分来计算(也就是说,如果我出生在2000年12月1日,今天的报告我将是12岁,而不是11岁)。 在这种情况下,您可以使用date运算符来提取年份值。

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

如果您在原始文档中存储年龄,答案将会简单得多(如Dmitry发布的那样,您可以在$group步骤中直接使用avgAge:{$avg:"$age"}

聚合框架是非常漂亮的,但有很多很酷的运算符,可以让你在“飞行中”计算这个缺失的年龄字段。

我将把聚合的每一步存储在一个variables中,以便更容易地看到发生了什么:

 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 ] } } }; 

现在你可以运行聚合:

 > 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 } > 

这不是简单的原因是目前聚合框架不支持直接减法date。 请投票支持https://jira.mongodb.org/browse/SERVER-6239这是针对下一个主要版本 – 一旦它被实现,它应该允许直接减去date(虽然你仍然需要将其转换为适当的粒度,在这种情况下大概是几年)。