Search This Blog

2024/04/22

MongoDb: $switch operator

We often used switch cases in javascript or C# or java as programming languages.

MongoDb also has switch case functionality.Lets explore switch case in mongodb.
It is about syntax only logic we already know.

$switch:
Evaluates a series of case expressions. When it finds an expression which
evaluates to true, $switch executes a specified expression and breaks out of the
control flow.

We will take a collection named grade as follows.

db.grades.insertMany([
{ "_id" : 1, "name" : "Susan Wilkes", "scores" : [ 87, 86, 78 ] },
{ "_id" : 2, "name" : "Bob Hanna", "scores" : [ 71, 64, 81 ] },
{ "_id" : 3, "name" : "James Torrelio", "scores" : [ 91, 84, 97 ] }
])

we will add Remarks based performance of student grade.if average score
is 90 or more we will give "Doing great!",If average score between 80
(inclusive) and 90 (exclusive) we will give "Doing pretty well."If average
score is less than 80 (exclusive) then will give Remarks "Needs improvement.".

db.grades.aggregate( [
{
$project:
{
"name" : 1,
"remarks" :
{
$switch:
{
branches: [
{
case: { $gte : [ { $avg : "$scores" }, 90 ] },
then: "Doing great!"
},
{
case: {
$and : [
{ $gte : [ { $avg : "$scores" }, 80 ] },
{ $lt : [ { $avg : "$scores" }, 90 ] }
]
},
then: "Doing pretty well."
},
{
case: { $lt : [ { $avg : "$scores" }, 80 ] },
then: "Needs improvement."
}
],
default: "No scores found."
}
}
}
}
] )

Output:
[
{ _id: 1, name: 'Susan Wilkes', remarks: 'Doing pretty well.' },
{ _id: 2, name: 'Bob Hanna', remarks: 'Needs improvement.' },
{ _id: 3, name: 'James Torrelio', remarks: 'Doing great!' }
]

Now we will re modify this grades document where scores will be
object array and rebuild this query

//drop collection if pre exists
db.alternateGrades.drop()

db.alternateGrades.insertMany([
{
_id : 1,
name : "Susan Wilkes",
scores: [
{subject:"math",score:87 },
{subject:"science",score:86 },
{subject:"social science",score:78 }
]
},
{
_id : 2,
name : "Bob Hanna",
scores : [
{subject:"math",score:67},
{subject:"science",score:93},
{subject:"social science",score:67}
]
},
{
_id : 3,
name : "James Torrelio",
scores : [
{subject:"math",score:91},
{subject:"science",score:84},
{subject:"social science",score:83}
]
}
])

Here is modified query

db.alternateGrades.aggregate( [
{
$project:
{
"name" : 1,
"averageScore": { $avg : "$scores.score" },
"remarks" :
{
$switch:
{
branches: [
{
case: { $gte : [ { $avg : "$scores.score" }, 90 ] },
then: "Doing great!"
},
{
case: {
$and : [
{ $gte : [ { $avg : "$scores.score" }, 80 ] },
{ $lt : [ { $avg : "$scores.score" }, 90 ] }
]
},
then: "Doing pretty well."
},
{
case: { $lt : [ { $avg : "$scores.score" }, 80 ] },
then: "Needs improvement."
}
],
default: "No scores found."
}
}
}
}
] )

Output:
[
{
_id: 1,
name: 'Susan Wilkes',
averageScore: 83.66666666666667,
remarks: 'Doing pretty well.'
},
{
_id: 2,
name: 'Bob Hanna',
averageScore: 75.66666666666667,
remarks: 'Needs improvement.'
},
{
_id: 3,
name: 'James Torrelio',
averageScore: 86,
remarks: 'Doing pretty well.'
}
]
The output is almost same just I added averageScore to verify if remarks are
given properly based on conditions decided.

Now suppose we decided to give remarks not based on average but based on individual
score in subject then,let us look into that query

db.alternateGrades.aggregate([
{
"$addFields": {
scores: {
$map: {
input: "$scores",
as: "score",
in: {
"$mergeObjects": [
"$$score",
{
"remark":{
$switch:
{
branches: [
{
case: { $gte : [ "$$score.score", 90 ] },
then: "Doing great!"
},
{
case: {
$and : [
{ $gte : [ "$$score.score", 80 ] },
{ $lt : [ "$$score.score", 90 ] }
]
},
then: "Doing pretty well."
},
{
case: { $lt : [ "$$score.score", 80 ] },
then: "Needs improvement."
}
],
default: "No scores found."
}
}
}
]
}
}
}
}
}
])

Output:
[
{
_id: 1,
name: 'Susan Wilkes',
scores: [
{ subject: 'math', score: 87, remark: 'Doing pretty well.' },
{ subject: 'science', score: 86, remark: 'Doing pretty well.' },
{
subject: 'social science',
score: 78,
remark: 'Needs improvement.'
}
]
},
{
_id: 2,
name: 'Bob Hanna',
scores: [
{ subject: 'math', score: 67, remark: 'Needs improvement.' },
{ subject: 'science', score: 93, remark: 'Doing great!' },
{
subject: 'social science',
score: 67,
remark: 'Needs improvement.'
}
]
},
{
_id: 3,
name: 'James Torrelio',
scores: [
{ subject: 'math', score: 91, remark: 'Doing great!' },
{ subject: 'science', score: 84, remark: 'Doing pretty well.' },
{
subject: 'social science',
score: 83,
remark: 'Doing pretty well.'
}
]
}
]

We can straight-way update our collection "alternateGrades" to hold
remarks as follows


db.alternateGrades.updateMany(
{},
[
{
$set: {
scores: {
$map: {
input: "$scores",
as: "score",
in: {
subject: "$$score.subject",
score: "$$score.score",
remark: {
$switch: {
branches: [
{
case: { $gte: [ "$$score.score", 90 ] },
then: "Doing great!"
},
{
case: {
$and: [
{ $gte: [ "$$score.score", 80 ] },
{ $lt: [ "$$score.score", 90 ] }
]
},
then: "Doing pretty well."
},
{
case: { $lt: [ "$$score.score", 80 ] },
then: "Needs improvement."
}
],
default: "No score found."
}
}
}
}
}
}
}
]
)

Here we are re-creating "scores" array where the lines

subject: "$$score.subject",
score: "$$score.score",

make sure that existing values remain intact and then it calculate "remark"
value using condition on score of that subject.

Lets once check how it is updated

db.alternateGrades.find({})

Output:
[
{
_id: 1,
name: 'Susan Wilkes',
scores: [
{ subject: 'math', score: 87, remark: 'Doing pretty well.' },
{ subject: 'science', score: 86, remark: 'Doing pretty well.' },
{
subject: 'social science',
score: 78,
remark: 'Needs improvement.'
}
]
},
{
_id: 2,
name: 'Bob Hanna',
scores: [
{ subject: 'math', score: 67, remark: 'Needs improvement.' },
{ subject: 'science', score: 93, remark: 'Doing great!' },
{
subject: 'social science',
score: 67,
remark: 'Needs improvement.'
}
]
},
{
_id: 3,
name: 'James Torrelio',
scores: [
{ subject: 'math', score: 91, remark: 'Doing great!' },
{ subject: 'science', score: 84, remark: 'Doing pretty well.' },
{
subject: 'social science',
score: 83,
remark: 'Doing pretty well.'
}
]
}
]

Here we can see that remark field is added in each element of scores
array based on conditions we put on score.

Now we will go further and in remark use subject name

Here is my query

db.alternateGrades.updateMany(
{},
[
{
$set: {
scores: {
$map: {
input: "$scores",
as: "score",
in: {
subject: "$$score.subject",
score: "$$score.score",
remark: {
$switch: {
branches: [
{
case: { $gte: [ "$$score.score", 90 ] },
then: {$concat: [`Doing great! in `,
"$$score.subject" ]}
},
{
case: {
$and: [
{ $gte: [ "$$score.score", 80 ] },
{ $lt: [ "$$score.score", 90 ] }
]
},
then: {$concat: [`Doing pretty well in `,
"$$score.subject" ]}
},
{
case: { $lt: [ "$$score.score", 80 ] },
then: {$concat: [`Needs improvement in `,
"$$score.subject" ]}
}
],
default: "No score found."
}
}
}
}
}
}
}
]
)

Lets once check once gain how it is updated

db.alternateGrades.find({})
Output:

[
{
_id: 1,
name: 'Susan Wilkes',
scores: [
{
subject: 'math',
score: 87,
remark: 'Doing pretty well in math'
},
{
subject: 'science',
score: 86,
remark: 'Doing pretty well in science'
},
{
subject: 'social science',
score: 78,
remark: 'Needs improvement in social science'
}
]
},
{
_id: 2,
name: 'Bob Hanna',
scores: [
{
subject: 'math',
score: 67,
remark: 'Needs improvement in math'
},
{
subject: 'science',
score: 93,
remark: 'Doing great! in science'
},
{
subject: 'social science',
score: 67,
remark: 'Needs improvement in social science'
}
]
},
{
_id: 3,
name: 'James Torrelio',
scores: [
{ subject: 'math', score: 91, remark: 'Doing great! in math' },
{
subject: 'science',
score: 84,
remark: 'Doing pretty well in science'
},
{
subject: 'social science',
score: 83,
remark: 'Doing pretty well in social science'
}
]
}
]

No comments:

Post a Comment