0

アプリで多数のユーザープロファイルデータを集約しようとしています。各ユーザーには、性別と民族性の属性が埋め込まれたプロファイルドキュメントがあります。

{
  '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を超えるレコードがあるため、出力はかなり不正確です。

4

1 に答える 1

2

以前の呼び出しからの出力で、reduce関数を再度呼び出すことができます。mapからの出力はreduceからの出力と同じである必要があります。現在のmap関数は、reduce関数とは異なるものを返します。次のようなものを試してください。

function map(){
  result = {'gender': {'male': 0, 'female': 0}, 'ethnicity': {}, 'count': 1};
  result['gender'][this.gender] = 1;
  result['ethnicity'][this.ethnicity] = 1;
  emit('demographics', result);
}

function reduce (key, values) {
  var reduced = {'gender': {'male':0,'female':0}, 'ethnicity': {}, 'count': 0};
  values.forEach(function(value) {
    reduced['gender']['male'] += value['gender']['male'];
    reduced['gender']['female'] += value['gender']['female'];
    for(ethnicity in value['ethnicity']){
      if(reduced['ethnicity'][ethnicity] === undefined)
        reduced['ethnicity'][ethnicity] = 0
      reduced['ethnicity'][ethnicity] += value['ethnicity'][ethnicity]
    }
    reduced['count'] += values.count;
  });
  return reduced;
}
于 2012-07-02T18:38:20.647 に答える