Проблема с монго-картой и агрегированием имен ключей - PullRequest
0 голосов
/ 24 ноября 2011

В моей базе данных есть коллекция, представляющая IP-адреса, полученные из разных источников. Образец которого выглядит так:

{ "_id" : ObjectId("4e71060444dce16174378b79"), "ip" : "xxx.xxx.xxx.xxx", "sources" : { "Source1" : NumberLong(52), "Source2" : NumberLong(7) } }

Каждый объект будет иметь один или несколько источников.

Моя цель - показать количество записей, сообщаемых каждым источником, не обязательно зная имена всех возможных источников (поскольку новые могут потенциально быть добавлены в любое время). Я попытался решить эту проблему с помощью функции карты карты, просто выдавая 1 для каждого ключа в исходном хеше каждого объекта, но, похоже, что-то не так с моим синтаксисом. Если я сделаю следующее:

var map_s = function(){
  for(var source in this.sources) {
    emit(source, 1);
  }
}

var red_s = function(key, values){
  var total = 0;
  values.forEach(function(){
    total++;
  });
  return total;
}

var op = db.addresses.mapReduce(map_s, red_s, {out: 'results'});
db.results.find().forEach(printjson);

Я получаю

{ "_id" : "Source1", "value" : 12 }
{ "_id" : "Source2", "value" : 230 }
{ "_id" : "Source3", "value" : 358 }
{ "_id" : "Source4", "value" : 398 }
{ "_id" : "Source5", "value" : 39 }
{ "_id" : "Source6", "value" : 420 }
{ "_id" : "Source7", "value" : 156 }

Что слишком мало для размера базы данных. Например, я получаю в оболочке следующее, если рассчитывать на определенный источник:

> db.addresses.count({"sources.Source4": {$exists: true}});
1260538

Где моя ошибка?

1 Ответ

1 голос
/ 28 ноября 2011

Да, в вашем методе редукции есть проблема, она должна быть идемпотентной.Помните, что при промежуточных результатах можно вызывать метод less () много раз.

Вместо

values.forEach(function(){
  total++;
});

Вам необходимо:

values.forEach(function(x){
  total += x;
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...