Puede hacerlo con el marco de agregación como una operación de "dos pasos". Que consiste en acumular primero los elementos en una matriz a través de $push
dentro de un $group
tubería, y luego usar $concat
con $reduce
en la matriz producida en proyección final:
db.collection.aggregate([
{ "$group": {
"_id": "$tag_id",
"client_id": { "$push": "$client_id" }
}},
{ "$addFields": {
"client_id": {
"$reduce": {
"input": "$client_id",
"initialValue": "",
"in": {
"$cond": {
"if": { "$eq": [ "$$value", "" ] },
"then": "$$this",
"else": {
"$concat": ["$$value", ",", "$$this"]
}
}
}
}
}
}}
])
También aplicamos $cond
aquí para evitar concatenar una cadena vacía con una coma en los resultados, por lo que se parece más a una lista delimitada.
FYI Hay un problema de JIRA SERVER-29339
que pide $reduce
para implementarse como una expresión acumulada
para permitir su uso directamente en un $group
etapa de tubería. No es probable que suceda pronto, pero teóricamente reemplazaría $push
en lo anterior y hacer de la operación una sola etapa del oleoducto. La sintaxis propuesta de muestra es sobre el problema de JIRA.
Si no tiene $reduce
(requiere MongoDB 3.4) luego simplemente publique el proceso del cursor:
db.collection.aggregate([
{ "$group": {
"_id": "$tag_id",
"client_id": { "$push": "$client_id" }
}},
]).map( doc =>
Object.assign(
doc,
{ "client_id": doc.client_id.join(",") }
)
)
Lo que luego lleva a la otra alternativa de hacer esto usando mapReduce
si realmente debes:
db.collection.mapReduce(
function() {
emit(this.tag_id,this.client_id);
},
function(key,values) {
return [].concat.apply([],values.map(v => v.split(","))).join(",");
},
{ "out": { "inline": 1 } }
)
Que, por supuesto, genera en el mapReduce
específico forma de _id
y value
como el conjunto de claves, pero es básicamente la salida.
Usamos [].concat.apply([],values.map(...))
porque la salida del "reductor" puede ser una "cadena delimitada" porque mapReduce
funciona de manera incremental con grandes resultados y, por lo tanto, la salida del reductor puede convertirse en "entrada" en otra pasada. Por lo tanto, debemos esperar que esto pueda suceder y tratarlo en consecuencia.