I have data with the following structure:
{
name: "xyz",
numericProperty: 28
}
I want to do an aggregation group stage that gives me a structure of the shape:
{
_id: "xyz",
name: "xyz",
numericProperty: {
min: minvalue,
max: maxvalue,
avg: avgvalue
}
}
I have tried:
{
"$group":{
"_id":"$name",
"name":{"$first":"$name"},
"numericProperty": {
"min": {"$min":"$numericProperty"},
"max": {"$min":"$numericProperty"},
"avg": {"$min":"$numericProperty"}
}
}
}
which gives me the error The field 'numericProperty' must be an accumulator object
This led me to try (And I see now that $addFields
is not an accumulator object, but its own pipeline stage):
{
"$group":{
"_id":"$name",
"name":{"$first":"$name"},
"numericProperty": {"$addFields":[
"min": {"$min":"$numericProperty"},
"max": {"$min":"$numericProperty"},
"avg": {"$min":"$numericProperty"}]
}
}
}
Which gives me the error: The $addFields accumulator is a unary operator
And I have tried:
{
"$group":{
"_id":"$name",
"name":{"$first":"$name"},
"numericProperty.min": {"$min":"$numericProperty"}
"numericProperty.max": {"$min":"$numericProperty"}
"numericProperty.avg": {"$min":"$numericProperty"}
}
}
which gives me the error The field name 'numericProperty.min' cannot contain '.'
CodePudding user response:
$addFields
is not an accumulator operator. You may check the accumulator operator list.
Instead, the easier way will be adding the $project
stage to display numericProperty
as an object document.
db.collection.aggregate([
{
"$group": {
"_id": "$name",
"name": {
"$first": "$name"
},
"min": {
"$min": "$numericProperty"
},
"max": {
"$max": "$numericProperty"
},
"avg": {
"$avg": "$numericProperty"
}
}
},
{
$project: {
_id: 1,
name: 1,
numericProperty: {
min: "$min",
max: "$max",
avg: "$avg"
}
}
}
])
Without $project
stage, you need dual $group
stages with $mergeObjects
.
$mergeObjects overwrites the field values as it merges the documents. If documents to merge include the same field name, the field, in the resulting document, has the value from the last document merged for the field.
Use the $mergeObjects
in first/only one $group
stage, these $min
, $max
, $avg
will not work correctly. The $mergeObjects
operator will take the last value of the document as above mentioned.
Thus, it needs to have second $group
stage for $mergeObjects
as the documents returned after the first $group
stage are with a unique _id
(non-duplicate name
).
db.collection.aggregate([
{
"$group": {
"_id": "$name",
"name": {
"$first": "$name"
},
"min": {
"$min": "$numericProperty"
},
"max": {
"$max": "$numericProperty"
},
"avg": {
"$avg": "$numericProperty"
}
}
},
{
$group: {
_id: "$name",
"name": {
"$first": "$name"
},
"numericProperty": {
"$mergeObjects": {
"min": "$min",
"max": "$max",
"avg": "$avg"
}
}
}
}
])