Reputation: 21
Below is one of my document from collection movies
:
{
"_id" : 4,
"startYear" : 1892,
"title" : "Un bon bock",
"originalTitle" : "Un bon bock",
"rating" : 6.4,
"type" : "short",
"numVotes" : 105,
"genres" : [
"Short",
"Animation"
]
}
I would like every document to have a field called normalizedRating
that is calculated as follows:
normalizedRating = (rating - min(rating)) / (max(rating) - min(rating))
So, I get document like:
{
"_id" : 4,
"startYear" : 1892,
"title" : "Un bon bock",
"originalTitle" : "Un bon bock",
"rating" : 6.4,
"type" : "short",
"numVotes" : 105,
"genres" : [
"Short",
"Animation"
],
"normalizedRating": 6.3
}
I am able to get the above result by using two different queries. I'm curious to know if it can be done using a single query.
Upvotes: 1
Views: 2449
Reputation: 17915
If You wanted to do it in one query, then try either one of these two :
Query 1 :
db.collection.aggregate([
{
$group: {
_id: "",
maxRating: { $max: "$rating" },
minRating: { $min: "$rating" },
data: { $push: "$$ROOT" },
},
},
{
$unwind: "$data",
},
{
$addFields: {
"data.normalizedRating": {
$divide: [
{ $subtract: ["$data.rating", "$minRating"] },
{ $subtract: ["$maxRating", "$minRating"] },
],
},
},
},
{
$replaceRoot: { newRoot: "$data" },
},
]);
Test : MongoDB-playground
Query 2 :
db.collection.aggregate([
{
$facet: {
data: [{ $match: {} }],
ratingValues: [
{
$group: {
_id: "",
maxRating: { $max: "$rating" },
minRating: { $min: "$rating" },
},
},
],
},
},
{
$unwind: "$data",
},
{
$unwind: "$ratingValues",
},
{
$addFields: {
"data.normalizedRating": {
$divide: [
{ $subtract: ["$data.rating", "$ratingValues.minRating"] },
{ $subtract: ["$ratingValues.maxRating", "$ratingValues.minRating"] },
],
},
},
},
{
$project: { ratingValues: 0 },
},
{
$replaceRoot: { newRoot: "$data" },
},
]);
Test : MongoDB-playground
At end of the day if your dataset is medium one then these can perform good, but on huge datasets these might or might not work well - I would say to split this task into two to do some work in code or multiple calls if really needed or try to implement the same task using mapReduce if aggregation is really slow.
Upvotes: 1