2014-12-04 4 views
1

У меня есть коллекция со следующими даннымиMongoDB nodejs MapReduce

{ 
    id:1, 
    uid:'a1', 
    cat:'main', 
    subject:'Hello', 
}, 
{ 
    id:2, 
    uid:'a1', 
    cat:'a' 
}, 
{ 
    id:3, 
    uid:'a1', 
    cat:'b' 
}, 

в вышеуказанной коллекции я хочу найти { cat:'main' } и хотите получить записи в структуре ниже

[{ 
id:1, 
uid:'a1', 
category:'main', 
subject:'Hello', 
}, 
{ 
id:2, 
uid:'a1', 
category:'a', 
subject:'Hello' 
}, 
{ 
id:3, 
uid:'a1', 
category:'b', 
subject:'Hello' 
}] 

так что я пытаюсь искать в сборнике, где subject присутствует только для категории main, а затем я должен получить другие записи, которые имеют одинаковые uid как категория main.

Это возможно при использовании mapReduce?

ответ

0

Существует два способа сделать это, используя конвейер агрегации. Функции сокращения карты не требуются.

Первый подход основан на предположении, что документы в категории main всегда будут вставлены перед другими документами для того же uid и всегда будет иметь id меньше, чем другие документы, имеющие один и тот же uid. Если этот вопрос будет учтен во время ввода документа, мы можем сортировать его на поле id и, кроме того, индексировать его.

  • Sort на основе поля индекса.
  • Group от uid раздел. Таким образом, первая запись для каждой группы будет записи категории main.
  • Match только те группы, у которых есть запись категории main.
  • Unwind все записи в каждой группе и применяют предмет первой записи ко всем записям в каждой группе.

Кодекс:

collection.aggregate([ 
{$sort:{"id":1}}, 
{$group:{"_id":"$uid", 
     "cat":{$first:"$cat"}, 
     "subject":{$first:"$subject"}, 
     "record":{$push:"$$ROOT"}}}, 
{$match:{"cat":"main"}}, 
{$unwind:"$record"}, 
{$project:{"_id":0, 
      "id":"$record.id", 
      "uid":"$_id", 
      "cat":"$record.cat", 
      "subject":"$subject"}} 
],function(err,resp){ 
    console.log(resp); 
}) 

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

Для определения записи категории main для каждой группы требуется дополнительный оператор проекции. Мы сортируем на основе этого прогнозируемого поля. Оставшаяся логика такая же.

db.collection.aggregate([ 
{$project:{"_id":0, 
      "id":1,"uid":1,"cat":1,"subject":1, 
      "isMainRecord":{$cond:[{$eq:["$cat","main"]},0,1]}}}, 
{$sort:{"isMainRecord":1}}, 
{$group:{"_id":"$uid", 
     "cat":{$first:"$cat"},"subject":{$first:"$subject"}, 
     "record":{$push:"$$ROOT"}}}, 
{$match:{"cat":"main"}}, 
{$unwind:"$record"}, 
{$project:{"_id":0,"id":"$record.id", 
      "uid":"$_id","cat":"$record.cat","subject":"$subject"}} 
],{allowDiskUse:true},function(err,resp){ 
console.log(resp); 
}) 
+0

благодарит за ваш ответ, я смог построить запрос, выполнив первый пример, но с тестовой записью в 1 миллион, когда я выполняю поиск с большим количеством атрибутов, таких как диапазон дат в соответствии с лимитом 25, результат получается почти 4-5 секунд, я думаю, это потому, что сначала отсортированы все записи, а затем группа применяется ко всем записям за 1 миллион? я прав ? все равно оптимизировать это? – Arian

+0

Да. Вы можете индексировать поле id в порядке возрастания и удалить первую операцию сортировки. – BatScream