Home > Enterprise >  Add structured properties during Mongodb $group aggregation stage
Add structured properties during Mongodb $group aggregation stage

Time:10-05

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

Sample Mongo Playground


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

Sample Mongo Playground (dual $group stages)

  • Related