En las versiones Modern MongoDB puede hacerlo. Todavía no puede aplicar "directamente" una matriz a $concat
, sin embargo, puede usar $reduce
para trabajar con los elementos de la matriz y producir esto:
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" ] }
}
}
}
}
}}
])
Combinando, por supuesto, con $indexOfArray
para no "concatenar" con el "_"
guión bajo cuando es el "primer" índice de la matriz.
También mi "deseo" adicional ha sido respondido con $sum
:
db.collection.aggregate([
{ "$addFields": {
"total": { "$sum": "$items.value" }
}}
])
En general, esto se plantea un poco con los operadores de agregación que toman una serie de elementos. La distinción aquí es que significa una "matriz" de "argumentos" proporcionados en la representación codificada en oposición a un "elemento de matriz" presente en el documento actual.
La única forma en que realmente puede hacer el tipo de concatenación de elementos dentro de una matriz presente en el documento es hacer algún tipo de opción de JavaScript, como con este ejemplo en mapReduce:
db.collection.mapReduce(
function() {
emit( this._id, { "values": this.values.join("_") } );
},
function() {},
{ "out": { "inline": 1 } }
)
Por supuesto, si en realidad no está agregando nada, entonces posiblemente el mejor enfoque sea simplemente hacer esa operación de "unión" dentro de su código de cliente en el procesamiento posterior de los resultados de su consulta. Pero si necesita usarse para algún propósito en varios documentos, entonces mapReduce será el único lugar donde podrá usarlo.
Podría añadir que "por ejemplo" me encantaría que algo así funcionara:
{
"items": [
{ "product": "A", "value": 1 },
{ "product": "B", "value": 2 },
{ "product": "C", "value": 3 }
]
}
Y en conjunto:
db.collection.aggregate([
{ "$project": {
"total": { "$add": [
{ "$map": {
"input": "$items",
"as": "i",
"in": "$$i.value"
}}
]}
}}
])
Pero no funciona así porque $add
espera argumentos en lugar de una matriz del documento. ¡Suspiro! :(. Parte del razonamiento "por diseño" para esto podría argumentarse que "solo porque" es una matriz o "lista" de valores singulares que se pasan del resultado de la transformación, no está "garantizado" que esos son en realidad valores de tipo numérico singular "válidos" que el operador espera. Al menos no en los métodos implementados actualmente de "verificación de tipo".
Eso significa que por ahora todavía tenemos que hacer esto:
db.collection.aggregate([
{ "$unwind": "$items" },
{ "$group": {
"_id": "$_id",
"total": { "$sum": "$items.value" }
}}
])
Y, lamentablemente, tampoco habría forma de aplicar dicho operador de agrupación para concatenar cadenas.
Por lo tanto, puede esperar algún tipo de cambio en esto, o esperar algún cambio que permita modificar una variable de ámbito externo dentro del ámbito de un $map
operación de alguna manera. Mejor aún, un nuevo $join
La operación también sería bienvenida. Pero estos no existen al momento de escribir, y probablemente no existirán por algún tiempo.