Группировать и считать в MongoDB - PullRequest
3 голосов
/ 25 ноября 2011

Я пытаюсь сгруппировать и посчитать количество элементов для каждой группы в mongodb 2.0.1, но пока безуспешно.

Моя схема БД выглядит так:

{
    "_id" : ObjectId("4ece7544853b4b0941000000"),
    "ResultSet" : {
            "Results" : [
                    {
                            "quality" : 87,
                            "state" : "Franche-Comté"
                    }
            ]
    }
}

Я пробовал все виды методов, следуя различным учебникам, но каждый раз это один и тот же результат: единственная нулевая группа ... чего я не понимаю, почему.

Лучший запрос, который ядо сих пор написал следующее:

db.extract_2000.group( {
            cond: { "ResultSet.Results.quality": {$exists: true} },
            key: {"ResultSet.Results.state": true}, 
            reduce: function(obj, glob) { glob.total++; glob.quality += obj.ResultSet.Results.quality },
            initial: { total: 0, quality: 0 },
            finalize: function(glob) {glob.avgquality = glob.quality / glob.total}
            })

Что возвращает (еще раз):

[
        {
                "ResultSet.Results.state" : null,
                "total" : 2000,
                "quality" : NaN,
                "avgquality" : NaN
        }
]

Что я делаю не так?

Ответы [ 2 ]

2 голосов
/ 26 ноября 2011

Это просто не будет работать как написано.Ключевая проблема здесь: key: {"ResultSet.Results.state": true}.ResultSet.Results это массив.Когда вы запрашиваете ResultSet.Results.state, вы подразумеваете, что какой-то тип цикла for будет выполнен здесь.Команда group просто не в состоянии это сделать.

Вместо этого попробуйте следующее M / R:

map = function() {
  // Note that we emit once per result
  foreach(var i in ResultSet.Results) {
    key = this.ResultSet.Results[i];
    value = { count: 1, 
      quality: this.ResultSet.Results[i].quality,
      avg_quality: 0
    };

    emit(key, value);
  }
}

reduce = function(key, values) {
  // note that results has same fields as emitted value
  var results = { count: 0, quality: 0, avg_quality: 0 };
  foreach(var i in values){
    results.count += values[i].count;
    results.quality += values[i].quality;
    // ignore avg_quality, we don't use it
  }
  return results;
}

Вам также придется написать finalize для среднего значения.

finalize = function(key, value) {
  if (value.count > 0)
    value.avg_quality = value.quality / value.count;

  return value;
}
0 голосов
/ 27 февраля 2013

Функция карты

map = function() {

    for(var i in this.Results) {
        emit(this.Results[i].state, 
            {quality: this.Results[i].quality, total: 1, avgquality: 0}
        );
    }
}

Функция уменьшения

reduce = function(key, values) {
    var data = {quality: 0, total: 0, avgquality: 0};

    for(var i=0; i<values.length; i++) {
        data.quality += values[i].quality;
        data.total += values[i].total;
    }
    return data;
}

В функции финализации вычисляется только среднее значение.

...