Reputation: 4840
I have collection of products and these products have assessments. I need select product with the highest average of assessment. The problem is I can group products by average but I cannot group by average and select product with highest average.
To reproduce my problem follow these steps:
Insert products:
db.products.insert([
{
name: "Product1",
price: 1000,
features: {
feature1: 0.8,
feature2: 23
},
tags: ["tag1", "tag2", "tag3", "tag4"],
assessments: [
{name: "John", assessment: 3},
{name: "Anna", assessment: 4},
{name: "Kyle", assessment: 3.6}
]
},
{
name: "Product2",
price: 1200,
features: {
feature1: 4,
feature2: 4000,
feature3: "SDS"
},
tags: ["tag1"],
assessments: [
{name: "John", assessment: 5},
{name: "Richard", assessment: 4.8}
]
},
{
name: "Product3",
price: 450,
features: {
feature1: 1.3,
feature2: 60
},
tags: ["tag1", "tag2"],
assessments: [
{name: "Anna", assessment: 5},
{name: "Robert", assessment: 4},
{name: "John", assessment: 4},
{name: "Julia", assessment: 3}
]
},
{
name: "Product4",
price: 900,
features: {
feature1: 1700,
feature2: 17
},
tags: ["tag1", "tag2", "tag3"],
assessments: [
{name: "Monica", assessment: 3},
{name: "Carl", assessment: 4}
]
}
])
And I want to group by avg of assessments and select product with max avg.
I do it following:
db.products.aggregate([
{ $unwind : "$assessments" },
{ $group:
{
_id: "$name",
avg_assessment: {$avg: "$assessments.assessment"}
}
},
{ $project:
{
_id: 0,
product: "$_id",
avg_assessment: 1
}
}
])
Result of this query is:
{ "avg_assessment" : 3.5, "product" : "Product4" }
{ "avg_assessment" : 4, "product" : "Product3" }
{ "avg_assessment" : 4.9, "product" : "Product2" }
{ "avg_assessment" : 3.533333333333333, "product" : "Product1" }
Nice. Then I try to select product with highest avg using following query:
db.products.aggregate([
{ $unwind : "$assessments" },
{ $group:
{
_id: "$name",
avg_assessment: { $max: {$avg: "$assessments.assessment"}}
}
},
{ $project:
{
_id: 0,
product: "$_id",
avg_assessment: 1
}
}
])
But the result is the same but with rounded up values:
{ "avg_assessment" : 4, "product" : "Product4" }
{ "avg_assessment" : 5, "product" : "Product3" }
{ "avg_assessment" : 5, "product" : "Product2" }
{ "avg_assessment" : 4, "product" : "Product1" }
What's going on? Where is a problem?
Upvotes: 0
Views: 1751
Reputation: 75964
You can try below aggregation. No $unwind
needed here.
Compute $avg
for each assessment followed by sort desc.
$group
with $first
to pick the assessment with highest avg value.
Add $project
stage to limit the fields.
db.products.aggregate([
{ "$addFields" : {"avg_assessment":{"$avg":"$assessments.assessment" }}},
{ "$sort":{"avg_assessment":-1}},
{ "$group":
{
"_id": null,
"highest_avg_assessment": { $first:"$$ROOT"}
}
}
])
Upvotes: 5
Reputation: 10918
This might help:
db.products.aggregate([
{ $unwind : "$assessments" },
{ $group:
{
_id: "$name",
avg_assessment: {$avg: "$assessments.assessment"}
}
},
{
$sort: { avg_assessment: -1 } // sort by avg_assessment descending
},
{
$limit: 1 // only return one document
}
])
Upvotes: 3