Du kan gøre det med aggregeringsrammen som en "to-trins" operation. Hvilket er først at akkumulere elementerne til et array via $push
inden for en $group
pipeline og derefter bruge $concat
med $reduce
på det producerede array i endelig projektion:
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"]
}
}
}
}
}
}}
])
Vi anvender også $cond
her for at undgå at sammenkæde en tom streng med et komma i resultaterne, så det ligner mere en afgrænset liste.
FYI Der er et JIRA-problem SERVER-29339
som beder om $reduce
skal implementeres som et akkumulatorudtryk
for at tillade dets brug direkte i en $group
pipeline fase. Det er ikke sandsynligt, at det snart vil ske, men det ville teoretisk set erstatte $push
i ovenstående og gør operationen til et enkelt rørledningstrin. Eksempel på foreslået syntaks er på JIRA-spørgsmålet.
Hvis du ikke har $reduce
(kræver MongoDB 3.4) så skal du bare efterbehandle markøren:
db.collection.aggregate([
{ "$group": {
"_id": "$tag_id",
"client_id": { "$push": "$client_id" }
}},
]).map( doc =>
Object.assign(
doc,
{ "client_id": doc.client_id.join(",") }
)
)
Hvilket så fører til det andet alternativ at gøre dette ved at bruge mapReduce
hvis du virkelig skal:
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 } }
)
Hvilket selvfølgelig udsender i den specifikke mapReduce
form for _id
og value
som et sæt nøgler, men det er dybest set outputtet.
Vi bruger [].concat.apply([],values.map(...))
fordi outputtet af "reduceren" kan være en "separeret streng", fordi mapReduce
arbejder trinvist med store resultater, og derfor kan output fra reduceren blive "input" på et andet gennemløb. Så vi skal forvente, at dette kan ske og behandle det derefter.