将$ group定义为mongo聚合查询中的列表

时间:2015-10-29 07:18:55

标签: mongodb mongodb-query aggregation-framework

mongo中的$ group似乎主要用于按相同的值进行分组。对于这些mongo文档:

{
    "tens" : [10,20,30,40],
    "fives" : [5,15,25,35]
}

{$ group:{_ id:“$ price”}}

会给我三张价格为5,10,20的文件。但是如果想将群组的定义扩展到“等于”以外的东西会怎样。 如果我有以下结构的字典怎么办:

{ "_id" : "fives", "quantity" : 30 }
{ "_id" : "tens" , "quantity" : 13 }

并希望将价格分别为“十”阵列的所有文件和“五个”阵列分组到另一个文档中。类似的东西:

try{
        $sqry = $con->prepare("SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(WrkHrs))) AS MHrsTotal, SEC_TO_TIME(SUM(TIME_TO_SEC(Overtime))) AS MOvtTotal,
        SEC_TO_TIME(SUM(TIME_TO_SEC(TotalOT))) AS GMTotal FROM actualot WHERE EmpID = :id AND ValidDate BETWEEN DATE(:start) AND
        DATE(:end) GROUP BY EmpID ORDER BY ValidDate ASC");
        $sqry->bindParam(':id',$rs['EmpID']);
        $sqry->bindParam(':start',$from);
        $sqry->bindParam(':end',$to);
        $sqry->execute();
    }
    catch(PDOException $e){
        echo $e->getMessage();
        exit();
    }

使用聚合管道实现这一点的任何方法,而不必诉诸Map-Reduce?

1 个答案:

答案 0 :(得分:1)

你可以写下这样的东西:

db.collection.aggregate([
    { "$group": {
        "_id": {
            "$cond": [
                { "$or": [
                    { "$eq": [ "$price", 5 ] },
                    { "$eq": [ "$price", 15 ] },
                    { "$eq": [ "$price", 25 ] },
                    { "$eq": [ "$price", 35 ] }
                ]},
                "fives",
                { "$cond": [
                    { "$or": [
                        { "$eq"; [ "$price", 10 ] },
                        { "$eq": [ "$price", 20 ] },
                        { "$eq": [ "$price", 30 ] },
                        { "$eq": [ "$price", 40 ] }
                    ]}
                ]},
                "tens",
                null
            ]
        },
        "quantity": { "$sum": "$quantity" }
    }}
])

本质上将查看值并确定它们是否匹配“五”或“十”以进行分组。您甚至可以从源列表中以编程方式构造该结构。

但它可能仍然有点简洁,如果你只是指以“五”或“十”结尾的值,那么就这样做:

db.collection.aggregate([
    { "$group": {
        "_id": {
            "$cond": [
                { "$eq": [ { "$mod": [ { "$divide": [ "$price", 5 ] }, 2 ] }, 0 ] },
                "tens",
                "fives"
            ]
        },
        "quantity": { "$sum": "$quantity" }
    }}
])

或者更复杂的数学和条件来检测不是“十”或“五”的内容,具体取决于内容。在你拥有的样本上工作得很好,但你需要调整它并决定如何处理其他值,如27,要么围绕它们,要么忽略它们。 (提示:除以5后的数字的模数和1不等于0表示它不能被5完全整除。

基本情况是$cond三元运算符,它是一个(if / then / else)条件,从第一个参数(if)计算,返回第二个true(然后)或者第三位false(其他)。

所以你只需要一个逻辑条件来评估“fives”或“tens”,然后返回分组键和模($mod)逻辑的值,其中当前price除以“五“是一个奇数/偶数,取决于除以”二“的余数。

因此$cond是评估条件并返回适当分组键的关键。另请查看聚合框架的math operators以及general operator list以了解这些用法的用法。

如果不使用mapReduce,你可以做很多事情,只要有可能就应该使用它们。