Puoi farlo con il framework di aggregazione come un'operazione "in due passaggi". Che consiste nell'accumulare prima gli elementi in un array tramite $push
con un $group
pipeline e quindi per utilizzare $concat
con $reduce
sull'array prodotto nella proiezione finale:
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"]
}
}
}
}
}
}}
])
Applichiamo anche $cond
qui per evitare di concatenare una stringa vuota con una virgola nei risultati, in modo che assomigli più a un elenco delimitato.
Cordiali saluti, c'è un problema JIRA SERVER-29339
che richiede $reduce
da implementare come espressione accumulatore
per consentirne l'utilizzo direttamente in un $group
fase del gasdotto. È improbabile che accada presto, ma in teoria sostituirà $push
in quanto sopra e rendere l'operazione un'unica fase della pipeline. La sintassi di esempio proposta riguarda il problema JIRA.
Se non hai $reduce
(richiede MongoDB 3.4) quindi è sufficiente pubblicare il cursore:
db.collection.aggregate([
{ "$group": {
"_id": "$tag_id",
"client_id": { "$push": "$client_id" }
}},
]).map( doc =>
Object.assign(
doc,
{ "client_id": doc.client_id.join(",") }
)
)
Il che poi porta all'altra alternativa di farlo usando mapReduce
se proprio devi:
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 } }
)
Che ovviamente esce nello specifico mapReduce
forma di _id
e value
come il set di chiavi, ma è fondamentalmente l'output.
Usiamo [].concat.apply([],values.map(...))
perché l'output del "riduttore" può essere una "stringa delimitata" perché mapReduce
lavora in modo incrementale con grandi risultati e quindi l'uscita del riduttore può diventare "input" in un altro passaggio. Quindi dobbiamo aspettarci che ciò possa accadere e trattarlo di conseguenza.