Mongodb aggregation operation $isNumber

This is another problem caused by MongoDB collections not forcing documents to have the same consistent structure. This feature of Mongodb does bring flexible and powerful advantages, but some of Mongodb's operators and features seem to pay for this flexible structure.

There are two questions this time. A certain temperature monitoring system uses systems produced by different sensor manufacturers. The temperature data returned by different manufacturers have different types, including numeric types and character types. Some sensors are damaged and return empty data.

Another issue is the results students achieved in school exams. The grades of different courses are entered into the system according to different entry methods. Some are graded based on scores and include the five levels ABCDF. Some courses include student grade points. Now when it’s time to evaluate student status, the average of the student’s grade points must be calculated. This embarrassment troubled the engineer.

Used in Mongodb aggregation operations, the method $isNumber is used to determine whether the field value or the return value of the expression is a numeric type.

definition

$isNumber, determines whether the type of the return value of the specified expression is a numeric type. If the return data type is one of Integer, Decimal, Double, or Long, $isNumber returns true. For other non-numeric types, null or the document does not have this field, it returns false.

$isNumber uses the following syntax to evaluate the expression. where expression is any available expression.

{$isNumber: <expression>}

application

Determine whether the field value is of numeric type

There is a sensor table that records the following information. There are various data types in the reading field.

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)] }
])

Use aggregate query to add a new field isNumber to the query result, and return the type of the reading field

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"
}

Modify the return field value based on the result of $isNumber

The student performance table grade contains student performance information. The grade field stores two data types, one is character type ABCDF, and the other is numeric type grade point results.

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
}])

Now we need to calculate the grade point average of two students.

  • Add a new field points to the query results to represent the student's grade points
  • Use $isNumber to determine whether the grade field is of numeric type. If it is of numeric type, it will be returned directly to the points field. If it is not of numeric type, it will be returned to the points field according to the grade correspondence. A-4.0, B-3.0, C-2.0, D-1.0, F-0.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"
        }
    }
}])

Run an aggregate query and return results

/* 1 */
{
	"_id" : 978451637,
	"GPA" : Double("3")
},

/* 2 */
{
	"_id" : 457864153,
	"GPA" : 3.5
}

Guess you like

Origin blog.csdn.net/wilsonzane/article/details/135248101