Danny Beyrer
Danny Beyrer

Reputation: 51

Mongodb aggregate pipeline $group and return Object with key/value pairs to the resulting groups

I have a ClientField collection with a property map_type which can be "conversion", "default", or "json". I would like to group all client fields by map_type and have the result be an object rather than an array. Is this possible to do using only the Mongodb aggregate pipeline?

//Example ClientField Object
{
    "client_name" : "StackOverflow",
    "map_type" : "conversion",
    "push_type" : "profile",
    "name" : "dateOfBirth",
    "conversion" : {
        "method" : "dateOfBirth",
        "params" : "dateOfBirth"
    },
    "json_path" : "dateOfBirth",
    "e_field_id" : "4",
}

My current aggregate pipeline is:

const fieldGroups = await ClientField.aggregate([
    { $match: { client_name: this.name, push_type: push_type } },
    { $group: { _id: "$map_type", fields: { $push: "$$ROOT" } } }
]);

which returns an array of groups with a fields array:

[ 
  { _id: 'default', fields: [ContactField] },
  { _id: 'conversion', fields: [ContactField] },
  { _id: 'json', fields: [ContactField] } 
]

My desired result is:

{
  default: [ClientField],
  conversion: [ClientField],
  json: [ClientField]
}

Upvotes: 1

Views: 1521

Answers (1)

mickl
mickl

Reputation: 49975

You need to collect all your grouping results into one document by using another $group. Then you can run $arrayToObject to set your previous stage grouping _id as key and run $replaceRoot to promote that new object to top level:

db.collection.aggregate([
    // $match
    {
        $group: {
            _id: "$map_type",
            fields: {
                $push: "$$ROOT"
            }
        }
    },
    {
        $group: {
            _id: null,
            root: { $push: { k: "$_id", v: "$fields" } }
        }
    },
    {
        $replaceRoot: { newRoot: { $arrayToObject: "$root" } }
    }
])

Upvotes: 1

Related Questions