与许多 ODM 实现一样,学说的核心(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,它提供了一个静态值 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" 或者是“分组依据”语句的一部分。 SQL 也是如此。
这里的其他“管道”阶段基本上是$match,它完成了“后分组”以便与“HAVING”子句具有相同的效果,最后是$project,它只是清理输出以具有所需的字段名称,而不是在所需的 _id ("group by") 键中复合。
这就是您在 MongoDB 中进行聚合的方式。
有关常见 SQL 操作的更多信息,请参阅核心文档中的SQL to Aggregation Mapping Chart。