Перевести с SQL на монго

0

Как это должно быть написано в MongoDB?

SELECT field1, field2, product, COUNT(product) as counter
FROM table
GROUP BY product
HAVING counter > 0

Я попробовал следующее: это почти копия из руководства Doctrine.

$query = $this->createQueryBuilder('AcmeBundle:Product')
    ->group(array('product'), array('count' => 0))
    ->reduce('function (obj, prev) { prev.count++; }')
    ->field('product, field1, field2, count')
;

Это только дает мне 1 элемент "count = 21", который, кажется, взял все продукты и подсчитал их вместе.

Теги:
mongodb-query
aggregation-framework
doctrine-odm

2 ответа

0

Структура агрегации обеспечивает простой способ обработки записей и возврата вычисленных результатов.
В файле YourDocumentNameRepository.php напишите следующие строки:

$qb = $this->createAggregationBuilder('Document\YourDocumentName');

/* First stage: group by product and calculate the number of rows foreach group. */
$qb->group()
   ->field('id')
   ->expression('$product')
   ->field('field1')
   ->first('$field1)
   ->field('field2')
   ->first('$field2')  
   ->field('counter')
   ->sum(1);

/* Second stage: similar to  HAVING counter > 0 in SQL*/
$qb->match()
   ->field('counter')
   ->gt(0);

/* Execute the request */
$results = $qb->execute();
return $results;

Вы можете прочитать документацию.

0

Как и многие реализации ODM, ядро доктрины (часть переноса mongodDB) построено "поверх" основного интерфейса родного драйвера для MongoDB. Это позволяет подвергать эти объекты драйверов, чтобы вы могли реализовать собственные методы MongoDB для выполнения своих запросов.

Я говорю об этом в целом, так как наилучшим вариантом для вашего запроса является структура агрегации MongoDB. Это высокопроизводительная реализация в собственном коде на сервере, поэтому не полагается на интерпретацию JavaScript для методов типа "уменьшить", как это реализовано другими методами. Вообще говоря, DSL плохо отображает менеджеров, которые пытаются быть "всеми вещами" и, следовательно, генерировать SQL. Концепции совершенно разные и, следовательно, оптимальны.

Однако, как оказалось, существует класс оболочки Collection, который вы можете использовать, не вдаваясь прямо в собственный драйвер. Он имеет собственную .aggregate() метода .aggregate(). Не хватает информации о том, как получить доступ к этому объекту, но вы можете проследить его по ссылке из первоначальной фиксации.

Но получение базового объекта драйвера довольно просто:

$mongoCollection = $dm->getConnection()->getMongo()
    ->selectCollection('collectionName');

$result = $mongoCollection->aggregate(
    array(
       array( '$group' => array(
           '_id' => array( 
               'field1' => '$field1',
               'field2' => '$field2',
               'product' => '$product'
           ),
           'counter' => array( '$sum' => 1 )
       )),
       array( '$match' => array( 
           'counter' => array( '$gt' => 0 )
       )),
       array( '$project' => array( 
           'field1' => '$_id.field1',
           'field2' => '$_id.field2,
           'product' => '$_id.product',
           'counter' => 1
       ))
    )
);

Это использует оператор конвейера $group для выполнения фактической "группировки" с помощью указанного _id. Это может быть "составной ключ", как в этом случае, поэтому все поля берутся в совокупности. Любые поля, которые вы не хотите "группировать по", используются с операторами группировки, такими как $sum здесь, которые снабжаются статическим значением 1 для представления "подсчета" совпадений.

Если вы просто хотите "группировать по" значения поля "продукт", то другие поля в вашем результате также должны находиться под оператором группировки. Возможно, что-то вроде $first:

$result = $mongoCollection->aggregate(
    array(
       array( '$group' => array(
           '_id' => '$product',
           'field1' => array( '$first' => '$field1' ),
           'field2' => array( '$first' => '$field2' ),
           'counter' => array( '$sum' => 1 )
       )),
       array( '$match' => array( 
           'counter' => array( '$gt' => 0 )
       )),
       array( '$project' => array(
           '_id' => 0,
           'product' => '$_id',
           'field1' => 1,
           'field2' => 1,
           'counter' => 1
       ))
    )
);

Но любые поля, которые вы хотите, должны подчиняться "оператору группировки" или являться частью оператора "group by". То же самое верно для SQL.

Другие "конвейерные" этапы здесь в основном соответствуют $match которые выполняются "post grouping", чтобы иметь тот же эффект, что и предложение HAVING, и, наконец, $project который просто очищает результат, чтобы иметь нужные имена полей чем быть сложным в пределах требуемого _id ("group by").

Это то, как вы делаете агрегацию в MongoDB.

Дополнительные сведения об общих операциях SQL см. В таблице сопоставления SQL-агрегации в основной документации.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню