从SQL转换为mongo

问题描述 投票:0回答:2

应该如何在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”,它似乎已经采取了所有产品并将它们计算在一起。

php mongodb mongodb-query aggregation-framework doctrine-odm
2个回答
0
投票

像许多ODM实现一样,doctrine(mongodDB包装部分)的核心构建在MongoDB的基本本机驱动程序接口之上。这允许暴露于这些驱动程序对象,因此您可以实现本机MongoDB方法来执行查询。

我这说是一般的,因为查询的最佳选择是MongoDB的aggregation framework。它是服务器上本机代码的高性能实现,因此不依赖于其他方法实现的“reduce”类型方法的JavaScript解释。一般来说,DSL不能很好地映射到试图成为“所有东西”的管理器,因此也会生成SQL。概念是完全不同的,因此是最佳的。

事实证明,有一个Collection包装类,您可以使用它而无需深入到本机驱动程序对象。它有自己的.aggregate()方法包装器。缺乏有关如何访问此对象的详细信息,但您可以跟踪original commit中的引用。

但是获取底层驱动程序对象非常简单:

$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 here,它提供了静态值1来表示匹配的“计数”。

如果您只想“分组”“产品”字段值,则结果中的其他字段也必须位于grouping operator下。也许像$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
       ))
    )
);

但是你想要的任何字段都必须遵守"grouping operator"或者是“group by”声明的一部分。 SQL也是如此。

这里的其他“管道”阶段基本上是$match,它是“后分组”,以便与“HAVING”子句具有相同的效果,最后$project只是清理输出以获得所需的字段名称而不是在所需的_id(“group by”)键内复合。

这就是你在MongoDB中进行聚合的方式。

有关常见SQL操作的更多信息,请参阅核心文档中的SQL to Aggregation Mapping Chart


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;

你可以read the documentation.

© www.soinside.com 2019 - 2024. All rights reserved.