qqilihq
qqilihq

Reputation: 11454

MongoDB aggregation: Aggregate array into keyed objects

I'd like to flatten document array into a keyed objects using the aggregation functionality. Here’s an example of my documents:

[ 
    {
        "_id": 1,
        "texts": [
            { "language": "english", "text": "hello" },
            { "language": "german", "text": "hallo" },
            { "language": "french", "text": "bonjour" }
        ]
    }, …
]

Expected result:

[
     {
        "_id": 1,
        "texts": {
            "english": "hello",
            "german": "hallo",
            "french": "bonjour"
        }
    }, …
]

I’ve looked at different operators, e.g. $map, but this seems to be focued on transforming array to array. I’d probably need a JS equivalent of $reduce, but couldn’t find a way of accumulating my values into an object.

Any ideas?

Upvotes: 2

Views: 2515

Answers (3)

Ashh
Ashh

Reputation: 46451

You can try this using $map and $arrayToObject aggregation in mongodb 3.4.4 and above

Just convert language field with key(k) and text with value(v) using $map and transform the array to object using $arrayToObject

db.collection.aggregate([
  { "$addFields": {
    "texts": {
      "$map": {
        "input": "$texts",
        "in": {
          "k": "$$this.language",
          "v": "$$this.text"
        }
      }
    }
  }},
  { "$addFields": {
    "texts": { "$arrayToObject": "$texts" }
  }}
])

Upvotes: 2

s7vr
s7vr

Reputation: 75934

You can also use $zip with $arrayToObject.

Something like

db.col.aggregate([{
  "$project": {
    "texts":{
     "$arrayToObject":{
       "$zip": {
        "inputs": [
          "$texts.language",
          "$texts.text"
        ]
      }
    }
  }}
}])

Upvotes: 3

mickl
mickl

Reputation: 49945

You need $map and $arrayToObject which converts an array of k-v pairs into single object:

db.col.aggregate([
    {
        $addFields: {
            texts: {
                $arrayToObject: {
                    $map: {
                        input: "$texts",
                        as: "text",
                        in: {
                            k: "$$text.language",
                            v: "$$text.text"
                        }
                    }
                }
            }
        }
    }
])

Upvotes: 4

Related Questions