Агрегация MapReduce на основе атрибутов, содержащихся вне документа - PullRequest
1 голос
/ 07 сентября 2011

Скажем, у меня есть коллекция "видов деятельности", каждая из которых имеет название, стоимость и местоположение:

{_id : 1 , name: 'swimming', cost: '3.40', location: 'kirkstall'}
{_id : 2 , name: 'cinema', cost: '6.50', location: 'hyde park'}
{_id : 3 , name: 'gig', cost: '10.00', location: 'hyde park'}

У меня также есть коллекция people, в которой для каждого действия записывается, сколькораз они планируют делать каждое в год:

{_id : 1 , name: 'russell', activities : { {1 : 9} , {2 : 4} , {3 : 21} }}

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

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

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

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

Это означает, что во время MapReduce для коллекции людей янужно знать место проведения мероприятий, которые они запланировали.Кто-нибудь может придумать хороший способ сделать это?

Мой лучший способ на данный момент (что является довольно мусором) - создание хранимой функции javascript, которая принимает массив action_ids, запрашивает коллекцию активности и возвращаеткарта активности и местоположения.Затем я вставил бы это в функцию map и определял ее местоположение.Это было бы довольно глупо, хотя, как я уже сказал, один и тот же запрос к коллекции activities будет выполняться один раз для каждого элемента в коллекции people.

1 Ответ

0 голосов
/ 07 сентября 2011

Я сделал это, обернув MapReduce в некоторый сохраненный JavaScript.

function (query) {

  var one = db.people.findOne(query);
  var activity_ids = [];
  for (var k in one.activities){
    activity_ids.push(parseInt(k));
  }

  var activity_location_map = {};
  db.activities.find({id : {$in : activity_ids}}).forEach(function(a){
    activity_location_map[a.id] = a.location;
  });


  return db.people.mapReduce(
    function map(){
      for (var k in this.activities){
        emit({location : activity_location_map[k]} , { total: this.activities[k] });
        emit({location: activity_location_map[k]} , { total: this.activities[k] });
      }
    },
    function reduce(key, values){
      var reduced = {total: 0};
      values.forEach(function(value){
        reduced.total += value.total;
      });

      return reduced;
    },
    {out : {inline: true}, scope : { activity_location_map : activity_location_map }}
  ).results;
}

Раздражает, и грязно, но это работает, и я не могу думать об этом лучше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...