アプリで多数のユーザープロファイルデータを集約しようとしています。各ユーザーには、性別と民族性の属性が埋め込まれたプロファイルドキュメントがあります。
{
'email': 'foo@email.com',
'profile': {
'gender': 'male',
'ethnicity': 'Hispanic'
}
}
このようなグループ関数を使用する場合:
db.respondents.group({
key: {},
initial: {'gender': {'male':0,'female':0}, 'ethnicity': {}, 'count': 0},
reduce: function (user, totals) {
var profile = user.profile;
totals.gender[profile.gender]++;
totals.ethnicity[profile.ethnicity] = (totals.ethnicity[profile.ethnicity] || 0);
totals.ethnicity[profile.ethnicity]++
totals.count++;
}
});
希望する形式で結果が得られます。
{
"gender" : {
"male" : ###,
"female" : ###
},
"ethnicity" : {
"Caucasian/White" : ###,
"Hispanic" : ###,
...
},
"count" : ###
}
もちろん、別のreduce関数を使用して、これをmap/reduceコマンドとして機能させるのに問題があります。合計を合計する方法がわかりません。それらは常に正しくありません。reduceからの出力は、mapからの入力と同じ形式である必要があることは承知していますが、reduceが機能する方法に何かが欠けているように感じます...
@Jennaに応答して、入力は次のようになります。
{
'email': 'foo@email.com',
'profile': {
'gender': 'male',
'ethnicity': 'Hispanic'
}
}
関数は次のとおりです。
function map(){
emit('demographics', this.profile)
}
function reduce (key, values) {
var reduced = {'gender': {'male':0,'female':0}, 'ethnicity': {}, 'count': 0};
values.forEach(function(value) {
reduced.gender[value.gender]++;
reduced['ethnicity'][value.ethnicity] = (reduced['ethnicity'][value.ethnicity] || 0);
reduced['ethnicity'][value.ethnicity]++;
reduced.count++;
});
return reduced;
}
出力は次のとおりです。
{
"_id": "demographics",
"value": {
"gender": {
"male": 76.0,
"female": 64.0
},
"ethnicity": {
"Caucasian/White": 109.0,
"Other": 5.0,
"Asian": 10.0,
"African-American": 8.0,
"Hispanic": 7.0,
"Native American": 1.0
},
"count": 141.0
}
}
データベースには100,000を超えるレコードがあるため、出力はかなり不正確です。