Получить подсчитанный массив для документа

У меня есть 2 коллекции: слова и фразы. Каждый документ слова имеет массив идентификаторов фраз. И каждая фраза может быть активной или неактивной.

Например :

слова:
{"word" => "hello", фразы => [1,2]}
{"word" => "table", фразы => [2]}

фразы:
{"id" => 1, "phrase" => "hello world!", "active" => 1}
{"id" => 2, "фраза" => "привет, я уже купил новую таблицу", "active" => 0}

Мне нужно получить количество активных фраз для каждого слова.

В php я делаю это так:
1. получить все слова
2. для каждого слова получить количество активных фраз с условием ['active' => 1]

Вопрос: Как я могу получить слова с активными фразами в одном запросе? Я попытался использовать MapReduce, но мне нужно сделать запрос для каждого слова, чтобы получить количество активных фраз.

UPD: В моей тестовой коллекции есть 92 000 фраз и 23 000 слов.

Я уже тестировал оба варианта: с петлей php для каждого слова, в котором я получаю фразу count и функцию aggreagation в манго.

Но я изменил конвейер агрегации в кометах ниже из-за фраз_данных. Это массив, поэтому я не могу использовать $ match на нем. Я использую $ recind после $ lookup.

[ '$unwind' => '$5'], [ '$lookup' => [ 'from' => 'phrases_926ee3bc9fa72b029e028ec90e282072ea0721d1', 'localField' => '5', 'foreignField' => '0', 'as' => 'phrases_data' ] ], [ '$unwind' => '$phrases_data'], [ '$match' => [ 'phrases_data.3' => 77] ], //phrases_data.3 => 77 it is similar to phrases_data.active => 1 [ '$group' => [ '_id' => ['word' => '$1', 'id' => '$0'], 'active_count' => [ '$sum' => 1] ] ], [ '$match' => [ 'active_count' => ['$gt' => 0]] ], [ '$sort' => [ 'active_count' => -1 ] ] 

Проблема состоит в том, что команда $ group занимает 80% времени процесса. И это намного медленнее, чем петля php. Вот мои результаты для коллекции тестов:

 1. Php loop (get words-> get phrases count for each word): 10 seconds 2. Aggregation function : 20 seconds 

Solutions Collecting From Web of "Получить подсчитанный массив для документа"

 db.words.aggregate([ { "$unwind" : "$phrases"}, { "$lookup": { "from": "phrases", "localField": "phrases", "foreignField": "id", "as": "phrases_data" } }, { "$match" : { "phrases_data.active" : 1} }, { "$group" : { "_id" : "$word", "active_count" : { $sum : 1 } } } ]); 

Вы можете использовать вышеуказанный конвейер агрегации:

  1. Размотайте массив фраз из документа коллекции документов в виде отдельного документа
  2. выполнять поиск (объединение) в коллекции фраз с использованием размороженных фраз
  3. отфильтровать фразы и проверить на активное использование $ match
  4. Наконец, групповые фразы по слову и счету с использованием суммы $ sum: 1

Вы можете использовать ниже агрегатный трубопровод в 3.4.

Вам не нужно $unwind идентификаторы массивов в версиях 3.3.4 и после.

https://stackoverflow.com/a/36647133/2683814

Следующий запрос присоединяется к words с набором phrases за которыми следует $filter + $size для подсчета активных строк.

 <?php $manager = new MongoDB\Driver\Manager("mongodb://localhost:27017"); $pipeline = [ [ '$lookup' => [ 'from' => 'phrases', 'localField' => 'phrases', 'foreignField' => 'id', 'as' => 'phrases' ] ], [ '$addFields' => [ 'phrases' => [ '$size'=> [ [ '$filter' => [ 'input' => '$phrases', 'as' => 'phrase', 'cond' => [ '$eq' => [ '$$phrase.active', 1, ] ], ], ], ], ], '_id' => 0 ], ], ]; $command = new \MongoDB\Driver\Command([ 'aggregate' => 'words', 'pipeline' => $pipeline ]); $cursor = $manager->executeCommand('test', $command); foreach($cursor as $key => $document) { var_dump($document); } ?>