LongHike
LongHike

Reputation: 4460

Using $map in aggregate $group

I need to analyze some mongo db collections. What I need to extract the names and values of a collection.

Heres's how far I got:

db.collection(coll.name)
  .aggregate([
    { $project: { arrayofkeyvalue: { $objectToArray: '$$ROOT' } } },
    { $unwind: '$arrayofkeyvalue' },
    {
      $group: {
        _id: null,
        allkeys: { $addToSet: '$arrayofkeyvalue.k' },
      },
    },
  ])
  .toArray();

This works quite nicely. I get all the keys. However I'd like to get the values too.

So, I thought "piece o' cake" and replaced the allkeys section with the allkeysandvalues section, which is supposed to create a map with key and value pairs.

Like this:

db.collection(coll.name)
  .aggregate([
    { $project: { arrayofkeyvalue: { $objectToArray: '$$ROOT' } } },
    { $unwind: '$arrayofkeyvalue' },
    {
      $group: {
        _id: null,
        allkeysandvalues: {
          $map: {
            input: '$arrayofkeyvalue',
            as: 'kv',
            in: {
              k: '$$kv.k',
              v: '$$kv.v',
            },
          },
        },
      },
    },
  ])
  .toArray();

But that's not working. I get the error message

MongoError: unknown group operator '$map'

Does anyone know hot to solve this?

Upvotes: 2

Views: 2634

Answers (2)

turivishal
turivishal

Reputation: 36114

MongoError: unknown group operator '$map'

You can not use $map operator in $group stage directly in root level,

you can try adding one more group stage,

  • $group by k (key) and get the first v (value)
  • $group by null and construct the array of key-value pair
  • $arrayToObject convert key-value pair array to object
db.collection(coll.name).aggregate([
  { $project: { arrayofkeyvalue: { $objectToArray: "$$ROOT" } } },
  { $unwind: "$arrayofkeyvalue" },
  {
    $group: {
      _id: "$arrayofkeyvalue.k",
      value: { $first: "$arrayofkeyvalue.v" }
    }
  },
  {
    $group: {
      _id: null,
      allkeysandvalues: { $push: { k: "$_id", v: "$value" } }
    }
  },
  { $project: { allkeysandvalues: { $arrayToObject: "$allkeysandvalues" } } }
])

Playground

Upvotes: 3

mickl
mickl

Reputation: 49975

The $group pipeline stage requires accumulator expression so you have to use $push instead of $map:

{
    $group: {
        _id: null,
        allkeysandvalues: {
            $push: "$arrayofkeyvalue"
        }
    }
}

or

{
    $group: {
        _id: null,
        allkeysandvalues: {
            $push: {
                k: "$arrayofkeyvalue.k",
                v: "$arrayofkeyvalue.v"
            }
        }
    }
}

which returns the same result.

Please note that arrayofkeyvalue is an object since you run $unwind prior to $group

Mongo Playground

Upvotes: 3

Related Questions