Reputation: 11454
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
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
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
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