Можете да го направите с рамката за агрегиране като операция в "две стъпки". Което е първо да натрупате елементите в масив чрез $push
с $group
тръбопровод и след това да използвате $concat
с $reduce
върху произведения масив в крайната проекция:
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"]
}
}
}
}
}
}}
])
Също така прилагаме $cond
тук, за да избегнете свързването на празен низ със запетая в резултатите, така че да изглежда по-скоро като списък с разделители.
FYI Има проблем с JIRA SERVER-29339
което изисква $reduce
да се внедри като акумулаторен израз
за да разрешите използването му директно в $group
етап на тръбопровод. Няма вероятност да се случи скоро, но теоретично ще замени $push
в горното и направете операцията единичен тръбопроводен етап. Примерният предложен синтаксис е по въпроса с JIRA.
Ако нямате $reduce
(изисква MongoDB 3.4), след това просто обработете курсора след това:
db.collection.aggregate([
{ "$group": {
"_id": "$tag_id",
"client_id": { "$push": "$client_id" }
}},
]).map( doc =>
Object.assign(
doc,
{ "client_id": doc.client_id.join(",") }
)
)
Което след това води до другата алтернатива да направите това с помощта на mapReduce
ако наистина трябва:
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 } }
)
Което разбира се извежда в конкретния mapReduce
под формата на _id
и value
като набор от ключове, но основно е изходът.
Използваме [].concat.apply([],values.map(...))
защото изходът на "редуцента" може да бъде "разделен низ", защото mapReduce
работи постепенно с големи резултати и следователно изходът на редуктора може да стане "вход" при друго преминаване. Така че трябва да очакваме, че това може да се случи и да го третираме по съответния начин.