又是mongodb集合的不强制文档具有相同一致的结构产生的问题。Mongodb这种特点,确实带来了灵活强大的优势,但Mongodb的一些操作符和特性看起来在为这种灵活的结构买单。
这次有两个问题。某一个气温监控系统,采用了不同的传感器厂家生产的系统,不同厂家返回的温度数据有不同的类型,有数字类型的,有字符类型的。还有的传感器损坏,返回来了空数据。
另外一个问题是学生在学校考试当中取得的成绩。不同课程成绩按照不同的录入方式进入到系统。有的按照分数评级,录入了ABCDF这五个等级。而有的课程录入了学生绩点。现在到了评奖学籍的时候,要计算学生成绩绩点的平均值。这个为难坏了工程师。
Mongodb聚合操作用,方法$isNumber来判断字段值或表达式的返回值是否为数字类型。
$isNumber,判断指定表达式返回值的类型是否是数字类型。若返回数据类型是Integer, Decimal, Double, Long当中的一种,$isNumber返回true,其他的非数字类型,null或文档没有该字段,则返回false。
$isNumber使用下面的语法来判断表达式的值。其中expression是任何一个可用的表达式。
{$isNumber: }
有一个传感器表格,记录了下面的信息。其中reading字段中有各种数据类型。
db.sensors.insertMany([
{"_id": 1, "reading": NumberDecimal("26.0") },
{"_id": 2, "reading": NumberLong(25.0) },
{"_id": 3, "reading": NumberInt(24) },
{"_id": 4, "reading": 24.0 },
{"_id": 5, "reading": "24" },
{"_id": 6, "reading": [ NumberDecimal(26)] }
])
使用聚合查询,为查询结果添加新字段isNumber, 并返回reading字段的类型
db.sensors.aggregate([{
$addFields: { //在聚合查询中添加新字段isNumber和type
isNumber: {$isNumber: "$reading"}, //判断reading字段是否为数字类型
type: {$type: "$reading"}
}
}])
/* 1 */
{
"_id" : 1,
"reading" : Decimal128("26.0"),
"isNumber" : true,
"type" : "decimal"
},
/* 2 */
{
"_id" : 2,
"reading" : Long("25"),
"isNumber" : true,
"type" : "long"
},
/* 3 */
{
"_id" : 3,
"reading" : 24,
"isNumber" : true,
"type" : "int"
},
/* 4 */
{
"_id" : 4,
"reading" : 24,
"isNumber" : true,
"type" : "int"
},
/* 5 */
{
"_id" : 5,
"reading" : "24",
"isNumber" : false,
"type" : "string"
},
/* 6 */
{
"_id" : 6,
"reading" : [ Decimal128("26") ],
"isNumber" : false,
"type" : "array"
}
学生成绩表grade中包含了学生成绩信息。 其中grade字段保存了两种数据类型,一种是字符类型的ABCDF,另一种数字类型的绩点成绩。
db.grades.insertMany([{
"student_id": 457864153,
"class_id": "M044",
"class_desc": "Introduction to MongoDB 4.4",
"grade": "A"
},{
"student_id": 457864153,
"class_id": "M103",
"class_desc": "Basic Cluster Administration",
"grade": 3.0
},{
"student_id": 978451637,
"class_id": "M320",
"class_desc": "MongoDB data Modeling",
"grade": "C"
},{
"student_id": 978451637,
"class_id": "M001",
"class_desc": "MongoDB Basics",
"grade": 4.0
}])
现在需要计算两个学生的平均绩点。
db.grades.aggregate([{
$addFields: {
"points": {
$cond: {
if: {$isNumber: "$grade" },
then: "$grade",
else: {
$switch: {
branches: [
{ case: {$eq: ["$grade","A"]}, then: 4.0 },
{ case: {$eq: ["$grade","B"]}, then: 3.0 },
{ case: {$eq: ["$grade","C"]}, then: 2.0 },
{ case: {$eq: ["$grade","D"]}, then: 1.0 },
{ case: {$eq: ["$grade","F"]}, then: 0.0 },
]
}
}
}
}
}
},{
$group: {
_id: "$student_id",
GPA: {
$avg: "$points"
}
}
}])
运行聚合查询,返回结果
/* 1 */
{
"_id" : 978451637,
"GPA" : Double("3")
},
/* 2 */
{
"_id" : 457864153,
"GPA" : 3.5
}