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?
答案 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,你可以做很多事情,只要有可能就应该使用它们。