MongoDB & PHP - возвращение количества вложенных массивов - PullRequest
2 голосов
/ 13 сентября 2011

Представьте, что у меня есть коллекция MonogDB, содержащая следующие документы:

{name: 'Some Name', components: {ARRAY OF ITEMS}}

Как я могу вернуть имя и количество элементов в компонентах?Нужно ли использовать карту / уменьшить?

Я использую PHP-расширение Mongo.

РЕДАКТИРОВАТЬ: фрагмент текущего кода в PHP (работает), но я просто хочу подсчет компонентов

$fields = array(
    'name', 'components'
);
$cursor = $this->collection->find(array(), $fields);
$cursor->sort(array('created_ts' => -1));

if (empty($cursor) == true) {
    return array();
} else {
    return iterator_to_array($cursor);
}

Спасибо, Джим

Ответы [ 4 ]

1 голос
/ 14 сентября 2011

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

db.test.group({
 key: { name:true },
 reduce: function(obj,prev) {
  var count = 0;
  for(k in obj.components)
   count++;
  prev.count = count;
 },
 initial: { count: 0}
});

Вы упомянули, что у вас есть массив компонентов, но похоже, что вы храните компоненты как объект {}, а не как массив []. Вот почему мне пришлось добавить цикл в функцию Reduce, чтобы подсчитать все свойства объекта компонентов. Если бы это был массив, то вы могли бы просто использовать свойство .length.

В PHP это будет выглядеть примерно так (из Manual ):

$keys = array('name' => 1);
$initial = array('count' => 0);
$reduce =<<<JS
function(obj,prev) {
  var count = 0;
  for(k in obj.components)
   count++;
  prev.count = count;
 },
JS;

$m = new Mongo();
$db = $m->selectDB('Database');
$coll = $db->selectCollection('Collection');
$data = $coll->group($keys, $initial, $reduce);

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

0 голосов
/ 01 сентября 2016

Пробежал через это сегодня. Если вы используете новый драйвер с агрегатом, вы можете сделать это в php (с учетом этой схемы)

   {name: 'Some Name', components: {ARRAY OF ITEMS}}

В PHP:

   $collection = (new Client())->db->my_collection;
   $collection->aggregate([
       '$match' => ['name' => 'Some Name'],
       '$group' => [
             '_id' => null,
             'total'=> ['$sum' => "\$components"]
        ]
  ]);

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

https://docs.mongodb.com/manual/reference/operator/aggregation/size/

https://docs.mongodb.com/manual/reference/operator/aggregation/sum/

Проблема, с которой я столкнулся, состоит в том, что mongo помещает поля как "$field", а PHP это совсем не нравится из-за способа интерполяции переменных.Однако, как только вы выйдете из $, он будет работать нормально.

Я думаю, что для этого конкретного случая вам нужно сделать что-то подобное, но с $project вместо $group Как это

   $collection = (new Client())->db->my_collection;
   $collection->aggregate([
       '$match' => ['name' => 'Some Name'],
       '$project' => [
            'name' => "\$name",
            'total'=> ['$sum' => "\$components"]
        ]
   ]);

Это старый вопрос, но, поскольку ответа не найдено, я просто оставлю это здесь.

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

Вы можете использовать db.eval () и написать расчет в JavaScript.

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

Jim-

Это две отдельные операции; Если вы не хотите использовать подсчет PHP на результаты, которые вы получите, то вы бы сделали что-то вроде:

$m = new Mongo();
$db = $m->selectDB('yourDB');
$collection = $db->selectCollection('MyCollection');
$cursor = $collection->find(array(), array("name"=>1, "components"=>1));
foreach($cursor as $key){
   echo($key['name'].' components: '.count($key['components']);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...