今天我們要介紹$group
,它可以將資料進行分組,同時進行特定的運算,回傳運算後的結果。
例如:現在有每位學生三次段考的成績,老師需要針對這些成績進行計算。
{ _id: 1, student: 1, test: 1, math: 20, english: 45 },
{ _id: 2, student: 1, test: 2, math: 70, english: 78 },
{ _id: 3, student: 2, test: 1, math: 30, english: 80 },
{ _id: 4, student: 2, test: 2, math: 98, english: 100 },
{ _id: 5, student: 3, test: 1, math: 85, english: 83 },
{ _id: 6, student: 3, test: 2, math: 94, english: 70 }
情境一:我們想找出每一次段考數學最高分,和英文最低分的分數。
score.aggregate([
{
$group: {
_id: "$test", // 用來分組的欄位
maxMath: { $max: "$math" }, // 取math欄位的最大值
minEnglish: { $min: "$english" } // 取english的最小值
}
}
]);
最後會得到以下資料
{ _id: 1, maxMath: 85, minEnglish: 45 },
{ _id: 2, maxMath: 98, minEnglish: 70 }
在使用$group
必須注意,回傳資料裡面的_id
不會是原本的id值了,而是test這個欄位數值,以及原本的欄位資料,如果沒有特別用指令寫在新增的欄位裡面,基本上會在這一次的pipeline消失,不會往下傳給下一個aggregate pipeline。
情境二:我們想找出每一次段考數學第一、第二高分,可以使用$maxN
取前面最高的幾筆資料。
score.aggregate([
{
$group: {
_id: "$test",
maxMath: {
$maxN: {
input: "$math", // 要找最大值的欄位
n: 2 // 要取幾筆資料
}
}
}
}
]);
最後回傳
{ _id: 1, maxMath: [85, 30] },
{ _id: 2, maxMath: [98, 94] }
ps.$maxN
需要mongodb版本在5.2.以上才能使用。
情境三:計算每一次段考數學和英文的平均分數,可以使用$avg
來計算欄位的平均值。
score.aggregate([
{
$group: {
_id: "$test",
mathAvg: { $avg: "$math" },
englishAvg: { $avg: "$english" }
}
}
]);
最後回傳 (ps.事實上我用mongodb跑過,可以算到小數第15位,只是被我省略)
{ _id: 1, mathAvg: 45, englishAvg: 69.3 },
{ _id: 2, mathAvg: 87.3, englishAvg: 82.6 }
情境四:計算每一次段考數學標準差。
標準差的算法,官方有提供兩種操作符,$stdDevSamp和$stdDevPop,詳細差異請參考官方文件。
score.aggregate([
{
$group: {
_id: "$test",
mathStdDevSamp: { $stdDevSamp: "$math" },
mathStdDevPop: { $stdDevPop: "$math" }
}
}
]);
得到的結果,可以自己感受一下差異?
{ _id: 1, mathStdDevSamp: 35, mathStdDevPop: 28.577380332470412 },
{ _id: 2, mathStdDevSamp: 15.143755588800731, mathStdDevPop: 12.36482466066094 }
本篇文章同步放在我的部落格,大家有空可以進來逛逛