In the latest MongoDB versions, you have the ability to manipulate arrays using the $reduce
operator with documentation on reduce. Here is an example of how you can achieve this:
db.collection.aggregate([
{ "$addFields": {
"values": {
"$reduce": {
"input": "$values",
"initialValue": "",
"in": {
"$cond": {
"if": { "$eq": [ { "$indexOfArray": [ "$values", "$$this" ] }, 0 ] },
"then": { "$concat": [ "$$value", "$$this" ] },
"else": { "$concat": [ "$$value", "_", "$$this" ] }
}
}
}
}
}}
])
You can enhance this functionality by combining it with $indexOfArray
to avoid concatenating with an underscore when at the first index.
Another useful operator that has been introduced in MongoDB is $sum
:
db.collection.aggregate([
{ "$addFields": {
"total": { "$sum": "$items.value" }
}}
])
When working with aggregation operators that take an array of items, keep in mind the difference between an "array of arguments" and an "array element" within a document.
If you need to concatenate items within an array present in a document, one approach is to use JavaScript as demonstrated in the following mapReduce example:
db.collection.mapReduce(
function() {
emit( this._id, { "values": this.values.join("_") } );
},
function() {},
{ "out": { "inline": 1 } }
)
For scenarios where post-processing is possible outside of aggregation, consider performing join operations in client code. However, if such operations are required across documents, mapReduce remains the suitable option.
It would be ideal for functionalities like below to work seamlessly:
{
"items": [
{ "product": "A", "value": 1 },
{ "product": "B", "value": 2 },
{ "product": "C", "value": 3 }
]
}
As seen in this aggregation snippet:
db.collection.aggregate([
{ "$project": {
"total": { "$add": [
{ "$map": {
"input": "$items",
"as": "i",
"in": "$$i.value"
}}
]}
}}
])
However, current limitations do not support this method due to expectations from $add
operator arguments. An alternate solution involves unwinding and grouping the data to calculate totals.
While we may wish for advancements in these areas, existing methods require us to stick with the available options until further updates are made.