2014-06-19 3 views
2

У меня есть коллекция с документами с использованием схемы что-то вроде этого (некоторые члены отредактированный):MongoDB MapReduce - есть ли альтернатива Агрегации?

{ 
    "_id" : ObjectId("539f41a95d1887b57ab78bea"), 
    "answers" : { 
     "ratings" : { 
      "positivity" : [ 
       2, 
       3, 
       5 
      ], 
      "activity" : [ 
       4, 
       4, 
       3 
      ], 
    }, 
    "media" : [ 
     ObjectId("537ea185df872bb71e4df270"), 
     ObjectId("537ea185df872bb71e4df275"), 
     ObjectId("537ea185df872bb71e4df272") 
    ] 
} 

В этой схеме, первый, второй и третий рейтинги positivity соответствуют первой, второй и третьи записи в массиве media, соответственно. То же самое верно для оценок activity. Мне нужно рассчитать статистику для оценок positivity и activity относительно связанных с ними объектов media по всем документам коллекции. Прямо сейчас, я делаю это с MapReduce. Однако я хотел бы выполнить это с помощью Агрегационного трубопровода.

В идеале я хотел бы $unwind в media, answers.ratings.positivity и answers.ratings.activity массивов одновременно, так что я в конечном итоге, к примеру, следующие три документа, основанный на предыдущем примере:

[ 
    { 
     "_id" : ObjectId("539f41a95d1887b57ab78bea"), 
     "answers" : { 
      "ratings" : { 
       "positivity" : 2, 
       "activity" : 4 
      } 
     }, 
     "media" : ObjectId("537ea185df872bb71e4df270") 
    }, 
    { 
     "_id" : ObjectId("539f41a95d1887b57ab78bea"), 
     "answers" : { 
      "ratings" : { 
       "positivity" : 3 
       "activity" : 4 
      } 
     }, 
     "media" : ObjectId("537ea185df872bb71e4df275") 
    }, 
    { 
     "_id" : ObjectId("539f41a95d1887b57ab78bea"), 
     "answers" : { 
      "ratings" : { 
       "positivity" : 5 
       "activity" : 3 
      } 
     }, 
     "media" : ObjectId("537ea185df872bb71e4df272") 
    } 
] 

Есть каким-то образом добиться этого?

ответ

1

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

Если вы хотите использовать структуру агрегации, вам нужно немного изменить схему. Например, возьмем следующий документ схемы:

{ 
    "_id" : ObjectId("539f41a95d1887b57ab78bea"), 
    "answers" : { 
     "ratings" : { 
      "positivity" : [ 
       {k:1, v:2}, 
       {k:2, v:3}, 
       {k:3, v:5} 
      ], 
      "activity" : [ 
       {k:1, v:4}, 
       {k:2, v:4}, 
       {k:3, v:3} 
      ], 
    }}, 
    "media" : [ 
     {k:1, v:ObjectId("537ea185df872bb71e4df270")}, 
     {k:2, v:ObjectId("537ea185df872bb71e4df275")}, 
     {k:3, v:ObjectId("537ea185df872bb71e4df272")} 
    ] 
} 

Делая это, вы, по существу, добавив индекс объекта внутри массива. После этого это всего лишь вопрос разматывания всех массивов и сопоставления с ключом.

db.test.aggregate([{$unwind:"$media"}, 
{$unwind:"$answers.ratings.positivity"}, 
{$unwind:"$answers.ratings.activity"}, 
{$project:{"media":1, "answers.ratings.positivity":1,"answers.ratings.activity":1, 
    include:{$and:[ 
        {$eq:["$media.k", "$answers.ratings.positivity.k"]}, 
        {$eq:["$media.k", "$answers.ratings.activity.k"]} 
      ]}} 
}, 
{$match:{include:true}}]) 

И выход:

[ 
     { 
      "_id" : ObjectId("539f41a95d1887b57ab78bea"), 
      "answers" : { 
       "ratings" : { 
        "positivity" : { 
         "k" : 1, 
         "v" : 2 
        }, 
        "activity" : { 
         "k" : 1, 
         "v" : 4 
        } 
       } 
      }, 
      "media" : { 
       "k" : 1, 
       "v" : ObjectId("537ea185df872bb71e4df270") 
      }, 
      "include" : true 
     }, 
     { 
      "_id" : ObjectId("539f41a95d1887b57ab78bea"), 
      "answers" : { 
       "ratings" : { 
        "positivity" : { 
         "k" : 2, 
         "v" : 3 
        }, 
        "activity" : { 
         "k" : 2, 
         "v" : 4 
        } 
       } 
      }, 
      "media" : { 
       "k" : 2, 
       "v" : ObjectId("537ea185df872bb71e4df275") 
      }, 
      "include" : true 
     }, 
     { 
      "_id" : ObjectId("539f41a95d1887b57ab78bea"), 
      "answers" : { 
       "ratings" : { 
        "positivity" : { 
         "k" : 3, 
         "v" : 5 
        }, 
        "activity" : { 
         "k" : 3, 
         "v" : 3 
        } 
       } 
      }, 
      "media" : { 
       "k" : 3, 
       "v" : ObjectId("537ea185df872bb71e4df272") 
      }, 
      "include" : true 
     } 
    ] 

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

Смежные вопросы