5

私はこのような単純なdbレイアウトを持っています:

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になります。何かアイデアはありますか?

どうもありがとう

4

2 に答える 2

6

元のドキュメントに年齢を保存している場合、答えははるかに簡単になります(Dmitryが投稿したようavgAge:{$avg:"$age"}に、$groupステップでまっすぐに行うことができます。

ただし、Aggregation Frameworkは非常に優れており、この欠落している年齢フィールドを「オンザフライ」で計算できる多くの優れた演算子があります。

集計の各ステップを変数に格納して、何が起こっているのかを簡単に確認できるようにします。

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

これが単純ではない理由は、現在、AggregationFrameworkが日付の直接減算をサポートしていないためです。次のメジャーリリースの対象となるhttps://jira.mongodb.org/browse/SERVER-6239に投票してください。実装すると、日付を直接減算できるようになります(ただし、適切な粒度に変換する必要がありますが、この場合はおそらく数年)。

于 2012-10-20T20:50:51.617 に答える
4

日付オブジェクトを「平均化」することはできませんが、数値は平均化できます。日付をタイムスタンプ値に変換し、そこから平均を見つけることができます。ただし、それでも平均年齢ではありません。集計関数の外で、現在の日付から結果を差し引く必要があります。

もう1つのオプションは、日付の年の部分のみを使用して年齢を計算できると想定することです(つまり、2000年12月1日に生まれた場合、今日のレポートでは11歳ではなく12歳になります)。この場合、日付演算子を使用して年の値を抽出できます。

$project : {"sex"      : 1,
            "sexCount" : 1,
            "year" : {$year: "$birthday"},
           } 
},
$project : {"sex"      : 1,
            "sexCount" : 1,
            "age" : {$subtract: [2012, '$year']},
           } 
},
于 2012-10-20T19:26:36.067 に答える