Możesz to zrobić za pomocą struktury agregacji jako operacji „dwuetapowej”. Oznacza to najpierw zgromadzenie elementów w tablicy za pomocą $push
z $group
potoku, a następnie użyć $concat
z $reduce
na wytworzonej tablicy w rzucie końcowym:
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"]
}
}
}
}
}
}}
])
Stosujemy również $cond
tutaj, aby uniknąć łączenia pustego ciągu z przecinkiem w wynikach, dzięki czemu wygląda bardziej jak lista rozdzielana.
FYI Wystąpił problem z JIRA SERVER-29339
który prosi o $reduce
do zaimplementowania jako wyrażenie akumulacyjne
aby umożliwić jego użycie bezpośrednio w $group
etap rurociągu. Prawdopodobnie nie nastąpi to w najbliższym czasie, ale teoretycznie zastąpiłoby to $push
w powyższym i uczynić operację jednym etapem rurociągu. Przykładowa proponowana składnia dotyczy kwestii JIRA.
Jeśli nie masz $reduce
(wymaga MongoDB 3.4 ), a następnie po prostu przetwórz kursor:
db.collection.aggregate([
{ "$group": {
"_id": "$tag_id",
"client_id": { "$push": "$client_id" }
}},
]).map( doc =>
Object.assign(
doc,
{ "client_id": doc.client_id.join(",") }
)
)
Co następnie prowadzi do innej alternatywy wykonania tego przy użyciu mapReduce
jeśli naprawdę musisz:
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 } }
)
Który oczywiście wyprowadza w konkretnym mapReduce
forma _id
i value
jako zestaw kluczy, ale w zasadzie jest to wynik.
Używamy [].concat.apply([],values.map(...))
ponieważ wyjście „reduktora” może być „rozgraniczonym ciągiem”, ponieważ mapReduce
działa przyrostowo z dużymi wynikami i dlatego wyjście reduktora może stać się "wejściem" w innym przejściu. Musimy więc oczekiwać, że tak się stanie i odpowiednio to potraktować.